mirror of
https://github.com/gravitl/netmaker.git
synced 2024-09-20 23:36:18 +08:00
commit
b35554e3cf
38
auth/auth.go
38
auth/auth.go
|
@ -1,13 +1,8 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
|
@ -20,39 +15,6 @@ var (
|
|||
auth_provider *oauth2.Config
|
||||
)
|
||||
|
||||
// IsOauthUser - returns
|
||||
func IsOauthUser(user *models.User) error {
|
||||
var currentValue, err = FetchPassValue("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var bCryptErr = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(currentValue))
|
||||
return bCryptErr
|
||||
}
|
||||
|
||||
func FetchPassValue(newValue string) (string, error) {
|
||||
|
||||
type valueHolder struct {
|
||||
Value string `json:"value" bson:"value"`
|
||||
}
|
||||
newValueHolder := valueHolder{}
|
||||
var currentValue, err = logic.FetchAuthSecret()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var unmarshErr = json.Unmarshal([]byte(currentValue), &newValueHolder)
|
||||
if unmarshErr != nil {
|
||||
return "", unmarshErr
|
||||
}
|
||||
|
||||
var b64CurrentValue, b64Err = base64.StdEncoding.DecodeString(newValueHolder.Value)
|
||||
if b64Err != nil {
|
||||
logger.Log(0, "could not decode pass")
|
||||
return "", nil
|
||||
}
|
||||
return string(b64CurrentValue), nil
|
||||
}
|
||||
|
||||
func isUserIsAllowed(username, network string) (*models.User, error) {
|
||||
|
||||
user, err := logic.GetUser(username)
|
||||
|
|
|
@ -60,41 +60,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
platformRole, err := logic.GetRole(user.PlatformRoleID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if !platformRole.FullAccess {
|
||||
allNetworkRoles := make(map[models.NetworkID]struct{})
|
||||
if len(user.NetworkRoles) > 0 {
|
||||
for netID := range user.NetworkRoles {
|
||||
allNetworkRoles[netID] = struct{}{}
|
||||
|
||||
}
|
||||
}
|
||||
if len(user.UserGroups) > 0 {
|
||||
for userGID := range user.UserGroups {
|
||||
userG, err := logic.GetUserGroup(userGID)
|
||||
if err == nil {
|
||||
if len(userG.NetworkRoles) > 0 {
|
||||
for netID := range userG.NetworkRoles {
|
||||
allNetworkRoles[netID] = struct{}{}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
filteredNetworks := []models.Network{}
|
||||
for _, networkI := range allnetworks {
|
||||
if _, ok := allNetworkRoles[models.NetworkID(networkI.NetID)]; ok {
|
||||
filteredNetworks = append(filteredNetworks, networkI)
|
||||
}
|
||||
}
|
||||
allnetworks = filteredNetworks
|
||||
}
|
||||
|
||||
allnetworks = logic.FilterNetworksByRole(allnetworks, *user)
|
||||
logger.Log(2, r.Header.Get("user"), "fetched networks.")
|
||||
logic.SortNetworks(allnetworks[:])
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
|
|
@ -650,27 +650,8 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if servercfg.IsPro {
|
||||
go func() {
|
||||
users, err := logic.GetUsersDB()
|
||||
if err == nil {
|
||||
for _, user := range users {
|
||||
// delete role from user
|
||||
if netRoles, ok := user.NetworkRoles[models.NetworkID(node.Network)]; ok {
|
||||
delete(netRoles, models.GetRAGRoleName(node.Network, host.Name))
|
||||
user.NetworkRoles[models.NetworkID(node.Network)] = netRoles
|
||||
err = logic.UpsertUser(user)
|
||||
if err != nil {
|
||||
slog.Error("failed to get user", "user", user.UserName, "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
slog.Error("failed to get users", "error", err)
|
||||
}
|
||||
logic.DeleteRole(models.GetRAGRoleName(node.Network, host.Name))
|
||||
}()
|
||||
}
|
||||
|
||||
go logic.RemoveNetworkRoleFromUsers(*host, node)
|
||||
|
||||
apiNode := node.ConvertToAPINode()
|
||||
logger.Log(1, r.Header.Get("user"), "deleted ingress gateway", nodeid)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -11,8 +10,6 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/gravitl/netmaker/auth"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/email"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
|
@ -36,334 +33,7 @@ func userHandlers(r *mux.Router) {
|
|||
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserV1)))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(getPendingUsers))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(deleteAllPendingUsers))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(deletePendingUser))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(approvePendingUser))).Methods(http.MethodPost)
|
||||
|
||||
// User Role Handlers
|
||||
r.HandleFunc("/api/v1/users/roles", logic.SecurityCheck(true, http.HandlerFunc(listRoles))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/role", getRole).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/role", logic.SecurityCheck(true, http.HandlerFunc(createRole))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/users/role", logic.SecurityCheck(true, http.HandlerFunc(updateRole))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/v1/users/role", logic.SecurityCheck(true, http.HandlerFunc(deleteRole))).Methods(http.MethodDelete)
|
||||
|
||||
// User Group Handlers
|
||||
r.HandleFunc("/api/v1/users/groups", logic.SecurityCheck(true, http.HandlerFunc(listUserGroups))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/group", logic.SecurityCheck(true, http.HandlerFunc(getUserGroup))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/group", logic.SecurityCheck(true, http.HandlerFunc(createUserGroup))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/users/group", logic.SecurityCheck(true, http.HandlerFunc(updateUserGroup))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/v1/users/group", logic.SecurityCheck(true, http.HandlerFunc(deleteUserGroup))).Methods(http.MethodDelete)
|
||||
|
||||
// User Invite Handlers
|
||||
r.HandleFunc("/api/v1/users/invite", userInviteVerify).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/invite-signup", userInviteSignUp).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/users/invite", logic.SecurityCheck(true, http.HandlerFunc(inviteUsers))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/users/invites", logic.SecurityCheck(true, http.HandlerFunc(listUserInvites))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/invite", logic.SecurityCheck(true, http.HandlerFunc(deleteUserInvite))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/v1/users/invites", logic.SecurityCheck(true, http.HandlerFunc(deleteAllUserInvites))).Methods(http.MethodDelete)
|
||||
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/user/groups user listUserGroups
|
||||
//
|
||||
// Get all user groups.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func listUserGroups(w http.ResponseWriter, r *http.Request) {
|
||||
groups, err := logic.ListUserGroups()
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, groups, "successfully fetched user groups")
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/user/group user getUserGroup
|
||||
//
|
||||
// Get user group.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func getUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
gid, _ := url.QueryUnescape(r.URL.Query().Get("group_id"))
|
||||
if gid == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("group id is required"), "badrequest"))
|
||||
return
|
||||
}
|
||||
group, err := logic.GetUserGroup(models.UserGroupID(gid))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, group, "successfully fetched user group")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/v1/user/group user createUserGroup
|
||||
//
|
||||
// Create user groups.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func createUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
var userGroupReq models.CreateGroupReq
|
||||
err := json.NewDecoder(r.Body).Decode(&userGroupReq)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = logic.ValidateCreateGroupReq(userGroupReq.Group)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = logic.CreateUserGroup(userGroupReq.Group)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
for _, userID := range userGroupReq.Members {
|
||||
user, err := logic.GetUser(userID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if len(user.UserGroups) == 0 {
|
||||
user.UserGroups = make(map[models.UserGroupID]struct{})
|
||||
}
|
||||
user.UserGroups[userGroupReq.Group.ID] = struct{}{}
|
||||
logic.UpsertUser(*user)
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userGroupReq.Group, "created user group")
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/v1/user/group user updateUserGroup
|
||||
//
|
||||
// Update user group.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func updateUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
var userGroup models.UserGroup
|
||||
err := json.NewDecoder(r.Body).Decode(&userGroup)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = logic.ValidateUpdateGroupReq(userGroup)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = logic.UpdateUserGroup(userGroup)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userGroup, "updated user group")
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/v1/user/group user deleteUserGroup
|
||||
//
|
||||
// delete user group.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func deleteUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
gid, _ := url.QueryUnescape(r.URL.Query().Get("group_id"))
|
||||
if gid == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
|
||||
return
|
||||
}
|
||||
err := logic.DeleteUserGroup(models.UserGroupID(gid))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, nil, "deleted user group")
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/user/roles user listRoles
|
||||
//
|
||||
// lists all user roles.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func listRoles(w http.ResponseWriter, r *http.Request) {
|
||||
roles, err := logic.ListRoles()
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, roles, "successfully fetched user roles permission templates")
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/user/role user getRole
|
||||
//
|
||||
// Get user role permission templates.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func getRole(w http.ResponseWriter, r *http.Request) {
|
||||
rid, _ := url.QueryUnescape(r.URL.Query().Get("role_id"))
|
||||
if rid == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
|
||||
return
|
||||
}
|
||||
role, err := logic.GetRole(models.UserRole(rid))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, role, "successfully fetched user role permission templates")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/v1/user/role user createRole
|
||||
//
|
||||
// Create user role permission template.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func createRole(w http.ResponseWriter, r *http.Request) {
|
||||
var userRole models.UserRolePermissionTemplate
|
||||
err := json.NewDecoder(r.Body).Decode(&userRole)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = logic.ValidateCreateRoleReq(userRole)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
userRole.Default = false
|
||||
userRole.GlobalLevelAccess = make(map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope)
|
||||
err = logic.CreateRole(userRole)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userRole, "created user role")
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/v1/user/role user updateRole
|
||||
//
|
||||
// Update user role permission template.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func updateRole(w http.ResponseWriter, r *http.Request) {
|
||||
var userRole models.UserRolePermissionTemplate
|
||||
err := json.NewDecoder(r.Body).Decode(&userRole)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = logic.ValidateUpdateRoleReq(userRole)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
userRole.GlobalLevelAccess = make(map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope)
|
||||
err = logic.UpdateRole(userRole)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userRole, "updated user role")
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/v1/user/role user deleteRole
|
||||
//
|
||||
// Delete user role permission template.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func deleteRole(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
rid, _ := url.QueryUnescape(r.URL.Query().Get("role_id"))
|
||||
if rid == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
|
||||
return
|
||||
}
|
||||
err := logic.DeleteRole(models.UserRole(rid))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, nil, "created user role")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/users/adm/authenticate authenticate authenticateUser
|
||||
|
@ -723,18 +393,7 @@ func createUser(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
uniqueGroupsPlatformRole := make(map[models.UserRole]struct{})
|
||||
for groupID := range user.UserGroups {
|
||||
userG, err := logic.GetUserGroup(groupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
uniqueGroupsPlatformRole[userG.PlatformRole] = struct{}{}
|
||||
user.PlatformRoleID = userG.PlatformRole
|
||||
}
|
||||
if len(uniqueGroupsPlatformRole) > 1 {
|
||||
err = errors.New("only groups with same platform role can be assigned to an user")
|
||||
if err = logic.IsGroupsValid(user.UserGroups); err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
|
@ -763,6 +422,7 @@ func createUser(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("non-admins users can only be created on Pro version"), "forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
err = logic.CreateUser(&user)
|
||||
if err != nil {
|
||||
slog.Error("error creating new user: ", "user", user.UserName, "error", err.Error())
|
||||
|
@ -867,7 +527,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
if auth.IsOauthUser(user) == nil && userchange.Password != "" {
|
||||
if logic.IsOauthUser(user) == nil && userchange.Password != "" {
|
||||
err := fmt.Errorf("cannot update user's password for an oauth user %s", username)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
|
||||
return
|
||||
|
@ -990,367 +650,3 @@ func socketHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// Start handling the session
|
||||
go auth.SessionHandler(conn)
|
||||
}
|
||||
|
||||
// swagger:route GET /api/users_pending user getPendingUsers
|
||||
//
|
||||
// Get all pending users.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func getPendingUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
users, err := logic.ListPendingUsers()
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
logic.SortUsers(users[:])
|
||||
logger.Log(2, r.Header.Get("user"), "fetched pending users")
|
||||
json.NewEncoder(w).Encode(users)
|
||||
}
|
||||
|
||||
// swagger:route POST /api/users_pending/user/{username} user approvePendingUser
|
||||
//
|
||||
// approve pending user.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func approvePendingUser(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
username := params["username"]
|
||||
users, err := logic.ListPendingUsers()
|
||||
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
for _, user := range users {
|
||||
if user.UserName == username {
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fetchErr, "internal"))
|
||||
return
|
||||
}
|
||||
if err = logic.CreateUser(&models.User{
|
||||
UserName: user.UserName,
|
||||
Password: newPass,
|
||||
}); err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to create user: %s", err), "internal"))
|
||||
return
|
||||
}
|
||||
err = logic.DeletePendingUser(username)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal"))
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "approved "+username)
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/users_pending/user/{username} user deletePendingUser
|
||||
//
|
||||
// delete pending user.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func deletePendingUser(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
username := params["username"]
|
||||
users, err := logic.ListPendingUsers()
|
||||
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
for _, user := range users {
|
||||
if user.UserName == username {
|
||||
err = logic.DeletePendingUser(username)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal"))
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "deleted pending "+username)
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/users_pending/{username}/pending user deleteAllPendingUsers
|
||||
//
|
||||
// delete all pending users.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func deleteAllPendingUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
err := database.DeleteAllRecords(database.PENDING_USERS_TABLE_NAME)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to delete all pending users "+err.Error()), "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "cleared all pending users")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/v1/users/invite-signup user userInviteSignUp
|
||||
//
|
||||
// user signup via invite.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponse
|
||||
func userInviteSignUp(w http.ResponseWriter, r *http.Request) {
|
||||
email, _ := url.QueryUnescape(r.URL.Query().Get("email"))
|
||||
code, _ := url.QueryUnescape(r.URL.Query().Get("invite_code"))
|
||||
in, err := logic.GetUserInvite(email)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
if code != in.InviteCode {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid invite code"), "badrequest"))
|
||||
return
|
||||
}
|
||||
// check if user already exists
|
||||
_, err = logic.GetUser(email)
|
||||
if err == nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user already exists"), "badrequest"))
|
||||
return
|
||||
}
|
||||
var user models.User
|
||||
err = json.NewDecoder(r.Body).Decode(&user)
|
||||
if err != nil {
|
||||
logger.Log(0, user.UserName, "error decoding request body: ",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
if user.UserName != email {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username not matching with invite"), "badrequest"))
|
||||
return
|
||||
}
|
||||
if user.Password == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("password cannot be empty"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, inviteGroupID := range in.Groups {
|
||||
userG, err := logic.GetUserGroup(inviteGroupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("error fetching group id "+inviteGroupID.String()), "badrequest"))
|
||||
return
|
||||
}
|
||||
user.PlatformRoleID = userG.PlatformRole
|
||||
user.UserGroups = make(map[models.UserGroupID]struct{})
|
||||
user.UserGroups[inviteGroupID] = struct{}{}
|
||||
}
|
||||
if user.PlatformRoleID == "" {
|
||||
user.PlatformRoleID = models.ServiceUser
|
||||
}
|
||||
user.NetworkRoles = make(map[models.NetworkID]map[models.UserRole]struct{})
|
||||
err = logic.CreateUser(&user)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
// delete invite
|
||||
logic.DeleteUserInvite(email)
|
||||
logic.DeletePendingUser(email)
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
logic.ReturnSuccessResponse(w, r, "created user successfully "+email)
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/users/invite user userInviteVerify
|
||||
//
|
||||
// verfies user invite.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponse
|
||||
func userInviteVerify(w http.ResponseWriter, r *http.Request) {
|
||||
email, _ := url.QueryUnescape(r.URL.Query().Get("email"))
|
||||
code, _ := url.QueryUnescape(r.URL.Query().Get("invite_code"))
|
||||
err := logic.ValidateAndApproveUserInvite(email, code)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "invite is valid")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/v1/users/invite user inviteUsers
|
||||
//
|
||||
// invite users.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func inviteUsers(w http.ResponseWriter, r *http.Request) {
|
||||
var inviteReq models.InviteUsersReq
|
||||
err := json.NewDecoder(r.Body).Decode(&inviteReq)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
//validate Req
|
||||
uniqueGroupsPlatformRole := make(map[models.UserRole]struct{})
|
||||
for _, groupID := range inviteReq.Groups {
|
||||
userG, err := logic.GetUserGroup(groupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
uniqueGroupsPlatformRole[userG.PlatformRole] = struct{}{}
|
||||
}
|
||||
if len(uniqueGroupsPlatformRole) > 1 {
|
||||
err = errors.New("only groups with same platform role can be assigned to an user")
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, inviteeEmail := range inviteReq.UserEmails {
|
||||
// check if user with email exists, then ignore
|
||||
_, err := logic.GetUser(inviteeEmail)
|
||||
if err == nil {
|
||||
// user exists already, so ignore
|
||||
continue
|
||||
}
|
||||
invite := models.UserInvite{
|
||||
Email: inviteeEmail,
|
||||
Groups: inviteReq.Groups,
|
||||
InviteCode: logic.RandomString(8),
|
||||
}
|
||||
u, err := url.Parse(fmt.Sprintf("%s/invite?email=%s&invite_code=%s",
|
||||
servercfg.GetFrontendURL(), url.QueryEscape(invite.Email), url.QueryEscape(invite.InviteCode)))
|
||||
if err != nil {
|
||||
slog.Error("failed to parse to invite url", "error", err)
|
||||
return
|
||||
}
|
||||
invite.InviteURL = u.String()
|
||||
err = logic.InsertUserInvite(invite)
|
||||
if err != nil {
|
||||
slog.Error("failed to insert invite for user", "email", invite.Email, "error", err)
|
||||
}
|
||||
// notify user with magic link
|
||||
go func(invite models.UserInvite) {
|
||||
// Set E-Mail body. You can set plain text or html with text/html
|
||||
|
||||
e := email.UserInvitedMail{
|
||||
BodyBuilder: &email.EmailBodyBuilderWithH1HeadlineAndImage{},
|
||||
InviteURL: invite.InviteURL,
|
||||
}
|
||||
n := email.Notification{
|
||||
RecipientMail: invite.Email,
|
||||
}
|
||||
err = email.GetClient().SendEmail(context.Background(), n, e)
|
||||
if err != nil {
|
||||
slog.Error("failed to send email invite", "user", invite.Email, "error", err)
|
||||
}
|
||||
}(invite)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/users/invites user listUserInvites
|
||||
//
|
||||
// lists all pending invited users.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponseWithJson
|
||||
func listUserInvites(w http.ResponseWriter, r *http.Request) {
|
||||
usersInvites, err := logic.ListUserInvites()
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, usersInvites, "fetched pending user invites")
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/v1/users/invite user deleteUserInvite
|
||||
//
|
||||
// delete pending invite.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponse
|
||||
func deleteUserInvite(w http.ResponseWriter, r *http.Request) {
|
||||
email, _ := url.QueryUnescape(r.URL.Query().Get("invitee_email"))
|
||||
err := logic.DeleteUserInvite(email)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to delete user invite: ", email, err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "deleted user invite")
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/v1/users/invites user deleteAllUserInvites
|
||||
//
|
||||
// deletes all pending invites.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponse
|
||||
func deleteAllUserInvites(w http.ResponseWriter, r *http.Request) {
|
||||
err := database.DeleteAllRecords(database.USER_INVITES_TABLE_NAME)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to delete all pending user invites "+err.Error()), "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "cleared all pending user invites")
|
||||
}
|
||||
|
|
|
@ -93,18 +93,54 @@ func GetUsers() ([]models.ReturnUser, error) {
|
|||
return users, err
|
||||
}
|
||||
|
||||
// IsOauthUser - returns
|
||||
func IsOauthUser(user *models.User) error {
|
||||
var currentValue, err = FetchPassValue("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var bCryptErr = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(currentValue))
|
||||
return bCryptErr
|
||||
}
|
||||
|
||||
func FetchPassValue(newValue string) (string, error) {
|
||||
|
||||
type valueHolder struct {
|
||||
Value string `json:"value" bson:"value"`
|
||||
}
|
||||
newValueHolder := valueHolder{}
|
||||
var currentValue, err = FetchAuthSecret()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var unmarshErr = json.Unmarshal([]byte(currentValue), &newValueHolder)
|
||||
if unmarshErr != nil {
|
||||
return "", unmarshErr
|
||||
}
|
||||
|
||||
var b64CurrentValue, b64Err = base64.StdEncoding.DecodeString(newValueHolder.Value)
|
||||
if b64Err != nil {
|
||||
logger.Log(0, "could not decode pass")
|
||||
return "", nil
|
||||
}
|
||||
return string(b64CurrentValue), nil
|
||||
}
|
||||
|
||||
// CreateUser - creates a user
|
||||
func CreateUser(user *models.User) error {
|
||||
// check if user exists
|
||||
if _, err := GetUser(user.UserName); err == nil {
|
||||
return errors.New("user exists")
|
||||
}
|
||||
user.AuthType = models.BasicAuth
|
||||
if IsOauthUser(user) == nil {
|
||||
user.AuthType = models.OAuth
|
||||
}
|
||||
var err = ValidateUser(user)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to validate user", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
// encrypt that password so we never see it again
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 5)
|
||||
if err != nil {
|
||||
|
|
|
@ -674,71 +674,3 @@ func GetAllFailOvers() ([]models.Node, error) {
|
|||
}
|
||||
return igs, nil
|
||||
}
|
||||
|
||||
func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filteredNodes []models.Node) {
|
||||
|
||||
nodesMap := make(map[string]struct{})
|
||||
allNetworkRoles := []models.UserRole{}
|
||||
if len(user.NetworkRoles) > 0 {
|
||||
for _, netRoles := range user.NetworkRoles {
|
||||
for netRoleI := range netRoles {
|
||||
allNetworkRoles = append(allNetworkRoles, netRoleI)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(user.UserGroups) > 0 {
|
||||
for userGID := range user.UserGroups {
|
||||
userG, err := GetUserGroup(userGID)
|
||||
if err == nil {
|
||||
if len(userG.NetworkRoles) > 0 {
|
||||
for _, netRoles := range userG.NetworkRoles {
|
||||
for netRoleI := range netRoles {
|
||||
allNetworkRoles = append(allNetworkRoles, netRoleI)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, networkRoleID := range allNetworkRoles {
|
||||
userPermTemplate, err := GetRole(networkRoleID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
networkNodes := GetNetworkNodesMemory(nodes, userPermTemplate.NetworkID)
|
||||
if userPermTemplate.FullAccess {
|
||||
for _, node := range networkNodes {
|
||||
nodesMap[node.ID.String()] = struct{}{}
|
||||
}
|
||||
filteredNodes = append(filteredNodes, networkNodes...)
|
||||
continue
|
||||
}
|
||||
if rsrcPerms, ok := userPermTemplate.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok {
|
||||
if _, ok := rsrcPerms[models.AllRemoteAccessGwRsrcID]; ok {
|
||||
for _, node := range networkNodes {
|
||||
if _, ok := nodesMap[node.ID.String()]; ok {
|
||||
continue
|
||||
}
|
||||
if node.IsIngressGateway {
|
||||
nodesMap[node.ID.String()] = struct{}{}
|
||||
filteredNodes = append(filteredNodes, node)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for gwID, scope := range rsrcPerms {
|
||||
if _, ok := nodesMap[gwID.String()]; ok {
|
||||
continue
|
||||
}
|
||||
if scope.Read {
|
||||
gwNode, err := GetNodeByID(gwID.String())
|
||||
if err == nil && gwNode.IsIngressGateway {
|
||||
filteredNodes = append(filteredNodes, gwNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
@ -21,189 +19,8 @@ const (
|
|||
Unauthorized_Err = models.Error(Unauthorized_Msg)
|
||||
)
|
||||
|
||||
func GetSubjectsFromURL(URL string) (rsrcType models.RsrcType, rsrcID models.RsrcID) {
|
||||
urlSplit := strings.Split(URL, "/")
|
||||
rsrcType = models.RsrcType(urlSplit[1])
|
||||
if len(urlSplit) > 1 {
|
||||
rsrcID = models.RsrcID(urlSplit[2])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func networkPermissionsCheck(username string, r *http.Request) error {
|
||||
// at this point global checks should be completed
|
||||
user, err := GetUser(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 1")
|
||||
userRole, err := GetRole(user.PlatformRoleID)
|
||||
if err != nil {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
if userRole.FullAccess {
|
||||
return nil
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 2")
|
||||
// get info from header to determine the target rsrc
|
||||
targetRsrc := r.Header.Get("TARGET_RSRC")
|
||||
targetRsrcID := r.Header.Get("TARGET_RSRC_ID")
|
||||
netID := r.Header.Get("NET_ID")
|
||||
if targetRsrc == "" {
|
||||
return errors.New("target rsrc is missing")
|
||||
}
|
||||
if netID == "" {
|
||||
return errors.New("network id is missing")
|
||||
}
|
||||
if r.Method == "" {
|
||||
r.Method = http.MethodGet
|
||||
}
|
||||
if targetRsrc == models.MetricRsrc.String() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check if user has scope for target resource
|
||||
// TODO - differentitate between global scope and network scope apis
|
||||
netRoles := user.NetworkRoles[models.NetworkID(netID)]
|
||||
for netRoleID := range netRoles {
|
||||
err = checkNetworkAccessPermissions(netRoleID, username, r.Method, targetRsrc, targetRsrcID)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for groupID := range user.UserGroups {
|
||||
userG, err := GetUserGroup(groupID)
|
||||
if err == nil {
|
||||
netRoles := userG.NetworkRoles[models.NetworkID(netID)]
|
||||
for netRoleID := range netRoles {
|
||||
err = checkNetworkAccessPermissions(netRoleID, username, r.Method, targetRsrc, targetRsrcID)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("access denied")
|
||||
}
|
||||
|
||||
func checkNetworkAccessPermissions(netRoleID models.UserRole, username, reqScope, targetRsrc, targetRsrcID string) error {
|
||||
networkPermissionScope, err := GetRole(netRoleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 3", string(netRoleID))
|
||||
if networkPermissionScope.FullAccess {
|
||||
return nil
|
||||
}
|
||||
rsrcPermissionScope, ok := networkPermissionScope.NetworkLevelAccess[models.RsrcType(targetRsrc)]
|
||||
if targetRsrc == models.HostRsrc.String() && !ok {
|
||||
rsrcPermissionScope, ok = networkPermissionScope.NetworkLevelAccess[models.RemoteAccessGwRsrc]
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 4", string(netRoleID))
|
||||
if allRsrcsTypePermissionScope, ok := rsrcPermissionScope[models.RsrcID(fmt.Sprintf("all_%s", targetRsrc))]; ok {
|
||||
// handle extclient apis here
|
||||
if models.RsrcType(targetRsrc) == models.ExtClientsRsrc && allRsrcsTypePermissionScope.SelfOnly && targetRsrcID != "" {
|
||||
extclient, err := GetExtClient(targetRsrcID, networkPermissionScope.NetworkID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !IsUserAllowedAccessToExtClient(username, extclient) {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
}
|
||||
err = checkPermissionScopeWithReqMethod(allRsrcsTypePermissionScope, reqScope)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
if targetRsrc == models.HostRsrc.String() {
|
||||
if allRsrcsTypePermissionScope, ok := rsrcPermissionScope[models.RsrcID(fmt.Sprintf("all_%s", models.RemoteAccessGwRsrc))]; ok {
|
||||
err = checkPermissionScopeWithReqMethod(allRsrcsTypePermissionScope, reqScope)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 5", string(netRoleID))
|
||||
if targetRsrcID == "" {
|
||||
return errors.New("target rsrc id is empty")
|
||||
}
|
||||
if scope, ok := rsrcPermissionScope[models.RsrcID(targetRsrcID)]; ok {
|
||||
err = checkPermissionScopeWithReqMethod(scope, reqScope)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 6", string(netRoleID))
|
||||
return errors.New("access denied")
|
||||
}
|
||||
|
||||
func globalPermissionsCheck(username string, r *http.Request) error {
|
||||
user, err := GetUser(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userRole, err := GetRole(user.PlatformRoleID)
|
||||
if err != nil {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
if userRole.FullAccess {
|
||||
return nil
|
||||
}
|
||||
targetRsrc := r.Header.Get("TARGET_RSRC")
|
||||
targetRsrcID := r.Header.Get("TARGET_RSRC_ID")
|
||||
if targetRsrc == "" {
|
||||
return errors.New("target rsrc is missing")
|
||||
}
|
||||
if r.Method == "" {
|
||||
r.Method = http.MethodGet
|
||||
}
|
||||
if targetRsrc == models.MetricRsrc.String() {
|
||||
return nil
|
||||
}
|
||||
if (targetRsrc == models.HostRsrc.String() || targetRsrc == models.NetworkRsrc.String()) && r.Method == http.MethodGet && targetRsrcID == "" {
|
||||
return nil
|
||||
}
|
||||
if targetRsrc == models.UserRsrc.String() && username == targetRsrcID && (r.Method != http.MethodDelete) {
|
||||
return nil
|
||||
}
|
||||
rsrcPermissionScope, ok := userRole.GlobalLevelAccess[models.RsrcType(targetRsrc)]
|
||||
if !ok {
|
||||
return fmt.Errorf("access denied to %s rsrc", targetRsrc)
|
||||
}
|
||||
if allRsrcsTypePermissionScope, ok := rsrcPermissionScope[models.RsrcID(fmt.Sprintf("all_%s", targetRsrc))]; ok {
|
||||
return checkPermissionScopeWithReqMethod(allRsrcsTypePermissionScope, r.Method)
|
||||
|
||||
}
|
||||
if targetRsrcID == "" {
|
||||
return errors.New("target rsrc id is missing")
|
||||
}
|
||||
if scope, ok := rsrcPermissionScope[models.RsrcID(targetRsrcID)]; ok {
|
||||
return checkPermissionScopeWithReqMethod(scope, r.Method)
|
||||
}
|
||||
return errors.New("access denied")
|
||||
}
|
||||
|
||||
func checkPermissionScopeWithReqMethod(scope models.RsrcPermissionScope, reqmethod string) error {
|
||||
if reqmethod == http.MethodGet && scope.Read {
|
||||
return nil
|
||||
}
|
||||
if (reqmethod == http.MethodPatch || reqmethod == http.MethodPut) && scope.Update {
|
||||
return nil
|
||||
}
|
||||
if reqmethod == http.MethodDelete && scope.Delete {
|
||||
return nil
|
||||
}
|
||||
if reqmethod == http.MethodPost && scope.Create {
|
||||
return nil
|
||||
}
|
||||
return errors.New("operation not permitted")
|
||||
}
|
||||
var NetworkPermissionsCheck = func(username string, r *http.Request) error { return nil }
|
||||
var GlobalPermissionsCheck = func(username string, r *http.Request) error { return nil }
|
||||
|
||||
// SecurityCheck - Check if user has appropriate permissions
|
||||
func SecurityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
|
||||
|
@ -224,9 +41,9 @@ func SecurityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
|
|||
r.Header.Set("ismaster", "yes")
|
||||
} else {
|
||||
if isGlobalAccesss {
|
||||
err = globalPermissionsCheck(username, r)
|
||||
err = GlobalPermissionsCheck(username, r)
|
||||
} else {
|
||||
err = networkPermissionsCheck(username, r)
|
||||
err = NetworkPermissionsCheck(username, r)
|
||||
}
|
||||
}
|
||||
w.Header().Set("TARGET_RSRC", r.Header.Get("TARGET_RSRC"))
|
||||
|
|
|
@ -2,11 +2,8 @@ package logic
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
|
@ -23,172 +20,26 @@ var AdminPermissionTemplate = models.UserRolePermissionTemplate{
|
|||
FullAccess: true,
|
||||
}
|
||||
|
||||
var ServiceUserPermissionTemplate = models.UserRolePermissionTemplate{
|
||||
ID: models.ServiceUser,
|
||||
Default: true,
|
||||
FullAccess: false,
|
||||
DenyDashboardAccess: true,
|
||||
var GetFilteredNodesByUserAccess = func(user models.User, nodes []models.Node) (filteredNodes []models.Node) {
|
||||
return
|
||||
}
|
||||
|
||||
var PlatformUserUserPermissionTemplate = models.UserRolePermissionTemplate{
|
||||
ID: models.PlatformUser,
|
||||
Default: true,
|
||||
FullAccess: false,
|
||||
}
|
||||
|
||||
func UserRolesInit() {
|
||||
d, _ := json.Marshal(SuperAdminPermissionTemplate)
|
||||
database.Insert(SuperAdminPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
d, _ = json.Marshal(AdminPermissionTemplate)
|
||||
database.Insert(AdminPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
d, _ = json.Marshal(ServiceUserPermissionTemplate)
|
||||
database.Insert(ServiceUserPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
d, _ = json.Marshal(PlatformUserUserPermissionTemplate)
|
||||
database.Insert(PlatformUserUserPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
|
||||
}
|
||||
|
||||
func CreateDefaultNetworkRoles(netID string) {
|
||||
var NetworkAdminPermissionTemplate = models.UserRolePermissionTemplate{
|
||||
ID: models.UserRole(fmt.Sprintf("%s_%s", netID, models.NetworkAdmin)),
|
||||
Default: false,
|
||||
NetworkID: netID,
|
||||
FullAccess: true,
|
||||
NetworkLevelAccess: make(map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope),
|
||||
}
|
||||
|
||||
var NetworkUserPermissionTemplate = models.UserRolePermissionTemplate{
|
||||
ID: models.UserRole(fmt.Sprintf("%s_%s", netID, models.NetworkUser)),
|
||||
Default: false,
|
||||
FullAccess: false,
|
||||
NetworkID: netID,
|
||||
DenyDashboardAccess: false,
|
||||
NetworkLevelAccess: map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope{
|
||||
models.RemoteAccessGwRsrc: {
|
||||
models.AllRemoteAccessGwRsrcID: models.RsrcPermissionScope{
|
||||
Read: true,
|
||||
VPNaccess: true,
|
||||
},
|
||||
},
|
||||
models.ExtClientsRsrc: {
|
||||
models.AllExtClientsRsrcID: models.RsrcPermissionScope{
|
||||
Read: true,
|
||||
Create: true,
|
||||
Update: true,
|
||||
Delete: true,
|
||||
SelfOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
d, _ := json.Marshal(NetworkAdminPermissionTemplate)
|
||||
database.Insert(NetworkAdminPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
d, _ = json.Marshal(NetworkUserPermissionTemplate)
|
||||
database.Insert(NetworkUserPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
}
|
||||
|
||||
func DeleteNetworkRoles(netID string) {
|
||||
users, err := GetUsersDB()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, user := range users {
|
||||
if _, ok := user.NetworkRoles[models.NetworkID(netID)]; ok {
|
||||
delete(user.NetworkRoles, models.NetworkID(netID))
|
||||
UpsertUser(user)
|
||||
}
|
||||
|
||||
}
|
||||
userGs, _ := ListUserGroups()
|
||||
for _, userGI := range userGs {
|
||||
if _, ok := userGI.NetworkRoles[models.NetworkID(netID)]; ok {
|
||||
delete(userGI.NetworkRoles, models.NetworkID(netID))
|
||||
UpdateUserGroup(userGI)
|
||||
}
|
||||
}
|
||||
|
||||
roles, _ := ListRoles()
|
||||
for _, role := range roles {
|
||||
if role.NetworkID == netID {
|
||||
DeleteRole(role.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ListRoles - lists user roles permission templates
|
||||
func ListRoles() ([]models.UserRolePermissionTemplate, error) {
|
||||
data, err := database.FetchRecords(database.USER_PERMISSIONS_TABLE_NAME)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return []models.UserRolePermissionTemplate{}, err
|
||||
}
|
||||
userRoles := []models.UserRolePermissionTemplate{}
|
||||
for _, dataI := range data {
|
||||
userRole := models.UserRolePermissionTemplate{}
|
||||
err := json.Unmarshal([]byte(dataI), &userRole)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
userRoles = append(userRoles, userRole)
|
||||
}
|
||||
return userRoles, nil
|
||||
}
|
||||
|
||||
func ValidateCreateRoleReq(userRole models.UserRolePermissionTemplate) error {
|
||||
// check if role exists with this id
|
||||
_, err := GetRole(userRole.ID)
|
||||
if err == nil {
|
||||
return fmt.Errorf("role with id `%s` exists already", userRole.ID.String())
|
||||
}
|
||||
if len(userRole.NetworkLevelAccess) > 0 {
|
||||
for rsrcType := range userRole.NetworkLevelAccess {
|
||||
if _, ok := models.RsrcTypeMap[rsrcType]; !ok {
|
||||
return errors.New("invalid rsrc type " + rsrcType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
if userRole.NetworkID == "" {
|
||||
return errors.New("only network roles are allowed to be created")
|
||||
}
|
||||
var CreateRole = func(r models.UserRolePermissionTemplate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateUpdateRoleReq(userRole models.UserRolePermissionTemplate) error {
|
||||
roleInDB, err := GetRole(userRole.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if roleInDB.NetworkID != userRole.NetworkID {
|
||||
return errors.New("network id mismatch")
|
||||
}
|
||||
if roleInDB.Default {
|
||||
return errors.New("cannot update default role")
|
||||
}
|
||||
if len(userRole.NetworkLevelAccess) > 0 {
|
||||
for rsrcType := range userRole.NetworkLevelAccess {
|
||||
if _, ok := models.RsrcTypeMap[rsrcType]; !ok {
|
||||
return errors.New("invalid rsrc type " + rsrcType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
var FilterNetworksByRole = func(allnetworks []models.Network, user models.User) []models.Network {
|
||||
return allnetworks
|
||||
}
|
||||
|
||||
// CreateRole - inserts new role into DB
|
||||
func CreateRole(r models.UserRolePermissionTemplate) error {
|
||||
// check if role already exists
|
||||
if r.ID.String() == "" {
|
||||
return errors.New("role id cannot be empty")
|
||||
}
|
||||
_, err := database.FetchRecord(database.USER_PERMISSIONS_TABLE_NAME, r.ID.String())
|
||||
if err == nil {
|
||||
return errors.New("role already exists")
|
||||
}
|
||||
d, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(r.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
var IsGroupsValid = func(groups map[models.UserGroupID]struct{}) error {
|
||||
return nil
|
||||
}
|
||||
var RemoveNetworkRoleFromUsers = func(host models.Host, node models.Node) {}
|
||||
|
||||
var InitialiseRoles = func() {}
|
||||
var DeleteNetworkRoles = func(netID string) {}
|
||||
var CreateDefaultNetworkRoles = func(netID string) {}
|
||||
|
||||
// GetRole - fetches role template by id
|
||||
func GetRole(roleID models.UserRole) (models.UserRolePermissionTemplate, error) {
|
||||
|
@ -205,302 +56,10 @@ func GetRole(roleID models.UserRole) (models.UserRolePermissionTemplate, error)
|
|||
return ur, nil
|
||||
}
|
||||
|
||||
// UpdateRole - updates role template
|
||||
func UpdateRole(r models.UserRolePermissionTemplate) error {
|
||||
if r.ID.String() == "" {
|
||||
return errors.New("role id cannot be empty")
|
||||
}
|
||||
_, err := database.FetchRecord(database.USER_PERMISSIONS_TABLE_NAME, r.ID.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(r.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// DeleteRole - deletes user role
|
||||
func DeleteRole(rid models.UserRole) error {
|
||||
if rid.String() == "" {
|
||||
return errors.New("role id cannot be empty")
|
||||
}
|
||||
users, err := GetUsersDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role, err := GetRole(rid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if role.Default {
|
||||
return errors.New("cannot delete default role")
|
||||
}
|
||||
for _, user := range users {
|
||||
for userG := range user.UserGroups {
|
||||
ug, err := GetUserGroup(userG)
|
||||
if err == nil {
|
||||
if role.NetworkID != "" {
|
||||
for _, networkRoles := range ug.NetworkRoles {
|
||||
if _, ok := networkRoles[rid]; ok {
|
||||
err = errors.New("role cannot be deleted as active user groups are using this role")
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if user.PlatformRoleID == rid {
|
||||
err = errors.New("active roles cannot be deleted.switch existing users to a new role before deleting")
|
||||
return err
|
||||
}
|
||||
for _, networkRoles := range user.NetworkRoles {
|
||||
if _, ok := networkRoles[rid]; ok {
|
||||
err = errors.New("active roles cannot be deleted.switch existing users to a new role before deleting")
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return database.DeleteRecord(database.USER_PERMISSIONS_TABLE_NAME, rid.String())
|
||||
}
|
||||
|
||||
func ValidateCreateGroupReq(g models.UserGroup) error {
|
||||
// check platform role is valid
|
||||
role, err := GetRole(g.PlatformRole)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid platform role")
|
||||
return err
|
||||
}
|
||||
if role.NetworkID != "" {
|
||||
return errors.New("network role cannot be used as platform role")
|
||||
}
|
||||
// check if network roles are valid
|
||||
for _, roleMap := range g.NetworkRoles {
|
||||
for roleID := range roleMap {
|
||||
role, err := GetRole(roleID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid network role %s", roleID)
|
||||
}
|
||||
if role.NetworkID == "" {
|
||||
return errors.New("platform role cannot be used as network role")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func ValidateUpdateGroupReq(g models.UserGroup) error {
|
||||
// check platform role is valid
|
||||
role, err := GetRole(g.PlatformRole)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid platform role")
|
||||
return err
|
||||
}
|
||||
if role.NetworkID != "" {
|
||||
return errors.New("network role cannot be used as platform role")
|
||||
}
|
||||
for networkID := range g.NetworkRoles {
|
||||
userRolesMap := g.NetworkRoles[networkID]
|
||||
for roleID := range userRolesMap {
|
||||
netRole, err := GetRole(roleID)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid network role")
|
||||
return err
|
||||
}
|
||||
if netRole.NetworkID == "" {
|
||||
return errors.New("platform role cannot be used as network role")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateUserGroup - creates new user group
|
||||
func CreateUserGroup(g models.UserGroup) error {
|
||||
// check if role already exists
|
||||
if g.ID == "" {
|
||||
return errors.New("group id cannot be empty")
|
||||
}
|
||||
_, err := database.FetchRecord(database.USER_GROUPS_TABLE_NAME, g.ID.String())
|
||||
if err == nil {
|
||||
return errors.New("group already exists")
|
||||
}
|
||||
d, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(g.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// GetUserGroup - fetches user group
|
||||
func GetUserGroup(gid models.UserGroupID) (models.UserGroup, error) {
|
||||
d, err := database.FetchRecord(database.USER_GROUPS_TABLE_NAME, gid.String())
|
||||
if err != nil {
|
||||
return models.UserGroup{}, err
|
||||
}
|
||||
var ug models.UserGroup
|
||||
err = json.Unmarshal([]byte(d), &ug)
|
||||
if err != nil {
|
||||
return ug, err
|
||||
}
|
||||
return ug, nil
|
||||
}
|
||||
|
||||
// ListUserGroups - lists user groups
|
||||
func ListUserGroups() ([]models.UserGroup, error) {
|
||||
data, err := database.FetchRecords(database.USER_GROUPS_TABLE_NAME)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return []models.UserGroup{}, err
|
||||
}
|
||||
userGroups := []models.UserGroup{}
|
||||
for _, dataI := range data {
|
||||
userGroup := models.UserGroup{}
|
||||
err := json.Unmarshal([]byte(dataI), &userGroup)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
userGroups = append(userGroups, userGroup)
|
||||
}
|
||||
return userGroups, nil
|
||||
}
|
||||
|
||||
// UpdateUserGroup - updates new user group
|
||||
func UpdateUserGroup(g models.UserGroup) error {
|
||||
// check if group exists
|
||||
if g.ID == "" {
|
||||
return errors.New("group id cannot be empty")
|
||||
}
|
||||
_, err := database.FetchRecord(database.USER_GROUPS_TABLE_NAME, g.ID.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(g.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// DeleteUserGroup - deletes user group
|
||||
func DeleteUserGroup(gid models.UserGroupID) error {
|
||||
users, err := GetUsersDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range users {
|
||||
delete(user.UserGroups, gid)
|
||||
UpsertUser(user)
|
||||
}
|
||||
return database.DeleteRecord(database.USER_GROUPS_TABLE_NAME, gid.String())
|
||||
}
|
||||
|
||||
func HasNetworkRsrcScope(permissionTemplate models.UserRolePermissionTemplate, netid string, rsrcType models.RsrcType, rsrcID models.RsrcID, op string) bool {
|
||||
if permissionTemplate.FullAccess {
|
||||
return true
|
||||
}
|
||||
|
||||
rsrcScope, ok := permissionTemplate.NetworkLevelAccess[rsrcType]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_, ok = rsrcScope[rsrcID]
|
||||
return ok
|
||||
}
|
||||
func GetUserRAGNodes(user models.User) (gws map[string]models.Node) {
|
||||
logger.Log(0, "------------> 7. getUserRemoteAccessGwsV1")
|
||||
gws = make(map[string]models.Node)
|
||||
userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user)
|
||||
logger.Log(0, fmt.Sprintf("User Gw Access Scope: %+v", userGwAccessScope))
|
||||
_, allNetAccess := userGwAccessScope["*"]
|
||||
nodes, err := GetAllNodes()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
logger.Log(0, "------------> 8. getUserRemoteAccessGwsV1")
|
||||
for _, node := range nodes {
|
||||
if node.IsIngressGateway && !node.PendingDelete {
|
||||
if allNetAccess {
|
||||
gws[node.ID.String()] = node
|
||||
} else {
|
||||
gwRsrcMap := userGwAccessScope[models.NetworkID(node.Network)]
|
||||
scope, ok := gwRsrcMap[models.AllRemoteAccessGwRsrcID]
|
||||
if !ok {
|
||||
if scope, ok = gwRsrcMap[models.RsrcID(node.ID.String())]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if scope.VPNaccess {
|
||||
gws[node.ID.String()] = node
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Log(0, "------------> 9. getUserRemoteAccessGwsV1")
|
||||
return
|
||||
}
|
||||
|
||||
// GetUserNetworkRoles - get user network roles
|
||||
func GetUserNetworkRolesWithRemoteVPNAccess(user models.User) (gwAccess map[models.NetworkID]map[models.RsrcID]models.RsrcPermissionScope) {
|
||||
gwAccess = make(map[models.NetworkID]map[models.RsrcID]models.RsrcPermissionScope)
|
||||
logger.Log(0, "------------> 7.1 getUserRemoteAccessGwsV1")
|
||||
platformRole, err := GetRole(user.PlatformRoleID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if platformRole.FullAccess {
|
||||
gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope)
|
||||
return
|
||||
}
|
||||
logger.Log(0, "------------> 7.2 getUserRemoteAccessGwsV1")
|
||||
for netID, roleMap := range user.NetworkRoles {
|
||||
for roleID := range roleMap {
|
||||
role, err := GetRole(roleID)
|
||||
if err == nil {
|
||||
if role.FullAccess {
|
||||
gwAccess[netID] = map[models.RsrcID]models.RsrcPermissionScope{
|
||||
models.AllRemoteAccessGwRsrcID: {
|
||||
Create: true,
|
||||
Read: true,
|
||||
Update: true,
|
||||
VPNaccess: true,
|
||||
Delete: true,
|
||||
},
|
||||
models.AllExtClientsRsrcID: {
|
||||
Create: true,
|
||||
Read: true,
|
||||
Update: true,
|
||||
Delete: true,
|
||||
},
|
||||
}
|
||||
break
|
||||
}
|
||||
if rsrcsMap, ok := role.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok {
|
||||
if permissions, ok := rsrcsMap[models.AllRemoteAccessGwRsrcID]; ok && permissions.VPNaccess {
|
||||
if len(gwAccess[netID]) == 0 {
|
||||
gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope)
|
||||
}
|
||||
gwAccess[netID][models.AllRemoteAccessGwRsrcID] = permissions
|
||||
break
|
||||
} else {
|
||||
for gwID, scope := range rsrcsMap {
|
||||
if scope.VPNaccess {
|
||||
if len(gwAccess[netID]) == 0 {
|
||||
gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope)
|
||||
}
|
||||
gwAccess[netID][gwID] = scope
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Log(0, "------------> 7.3 getUserRemoteAccessGwsV1")
|
||||
return
|
||||
func UserRolesInit() {
|
||||
d, _ := json.Marshal(SuperAdminPermissionTemplate)
|
||||
database.Insert(SuperAdminPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
d, _ = json.Marshal(AdminPermissionTemplate)
|
||||
database.Insert(AdminPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
|
||||
}
|
||||
|
|
|
@ -356,6 +356,10 @@ func syncUsers() {
|
|||
if user.PlatformRoleID.String() != "" {
|
||||
continue
|
||||
}
|
||||
user.AuthType = models.BasicAuth
|
||||
if logic.IsOauthUser(&user) == nil {
|
||||
user.AuthType = models.OAuth
|
||||
}
|
||||
if len(user.NetworkRoles) == 0 {
|
||||
user.NetworkRoles = make(map[models.NetworkID]map[models.UserRole]struct{})
|
||||
}
|
||||
|
|
|
@ -12,6 +12,12 @@ type RsrcType string
|
|||
type RsrcID string
|
||||
type UserRole string
|
||||
type UserGroupID string
|
||||
type AuthType string
|
||||
|
||||
var (
|
||||
BasicAuth AuthType = "basic_auth"
|
||||
OAuth AuthType = "oauth"
|
||||
)
|
||||
|
||||
func (r RsrcType) String() string {
|
||||
return string(r)
|
||||
|
@ -128,6 +134,7 @@ type User struct {
|
|||
IsAdmin bool `json:"isadmin" bson:"isadmin"` // deprecated
|
||||
IsSuperAdmin bool `json:"issuperadmin"` // deprecated
|
||||
RemoteGwIDs map[string]struct{} `json:"remote_gw_ids"` // deprecated
|
||||
AuthType AuthType `json:"auth_type"`
|
||||
UserGroups map[UserGroupID]struct{} `json:"user_group_ids"`
|
||||
PlatformRoleID UserRole `json:"platform_role_id"`
|
||||
NetworkRoles map[NetworkID]map[UserRole]struct{} `json:"network_roles"`
|
||||
|
@ -144,6 +151,7 @@ type ReturnUser struct {
|
|||
UserName string `json:"username"`
|
||||
IsAdmin bool `json:"isadmin"`
|
||||
IsSuperAdmin bool `json:"issuperadmin"`
|
||||
AuthType AuthType `json:"auth_type"`
|
||||
RemoteGwIDs map[string]struct{} `json:"remote_gw_ids"` // deprecated
|
||||
UserGroups map[UserGroupID]struct{} `json:"user_group_ids"`
|
||||
PlatformRoleID UserRole `json:"platform_role_id"`
|
||||
|
|
|
@ -9,11 +9,11 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/auth"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
proLogic "github.com/gravitl/netmaker/pro/logic"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/microsoft"
|
||||
|
@ -89,7 +89,7 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
|
|||
if database.IsEmptyRecord(err) { // user must not exist, so try to make one
|
||||
if inviteExists {
|
||||
// create user
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fetchErr, "internal"))
|
||||
return
|
||||
|
@ -99,7 +99,7 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
|
|||
Password: newPass,
|
||||
}
|
||||
for _, inviteGroupID := range in.Groups {
|
||||
userG, err := logic.GetUserGroup(inviteGroupID)
|
||||
userG, err := proLogic.GetUserGroup(inviteGroupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("error fetching group id "+inviteGroupID.String()), "badrequest"))
|
||||
return
|
||||
|
@ -146,7 +146,7 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
|
|||
handleOauthUserNotAllowed(w)
|
||||
return
|
||||
}
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/auth"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
proLogic "github.com/gravitl/netmaker/pro/logic"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/github"
|
||||
|
@ -88,7 +88,7 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
|
|||
if database.IsEmptyRecord(err) { // user must not exist, so try to make one
|
||||
if inviteExists {
|
||||
// create user
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fetchErr, "internal"))
|
||||
return
|
||||
|
@ -99,7 +99,7 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
for _, inviteGroupID := range in.Groups {
|
||||
userG, err := logic.GetUserGroup(inviteGroupID)
|
||||
userG, err := proLogic.GetUserGroup(inviteGroupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("error fetching group id "+inviteGroupID.String()), "badrequest"))
|
||||
return
|
||||
|
@ -146,7 +146,7 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
|
|||
handleOauthUserNotAllowed(w)
|
||||
return
|
||||
}
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/auth"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
proLogic "github.com/gravitl/netmaker/pro/logic"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
|
@ -95,7 +95,7 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
|
|||
if inviteExists {
|
||||
// create user
|
||||
logger.Log(0, "CALLBACK ----> 4.0")
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fetchErr, "internal"))
|
||||
return
|
||||
|
@ -106,7 +106,7 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
logger.Log(0, "CALLBACK ----> 4.1")
|
||||
for _, inviteGroupID := range in.Groups {
|
||||
userG, err := logic.GetUserGroup(inviteGroupID)
|
||||
userG, err := proLogic.GetUserGroup(inviteGroupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("error fetching group id "+inviteGroupID.String()), "badrequest"))
|
||||
return
|
||||
|
@ -158,7 +158,7 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
|
|||
handleOauthUserNotAllowed(w)
|
||||
return
|
||||
}
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gravitl/netmaker/auth"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
|
@ -78,7 +77,7 @@ func HandleHeadlessSSOCallback(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
}
|
||||
newPass, fetchErr := auth.FetchPassValue("")
|
||||
newPass, fetchErr := logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/gravitl/netmaker/auth"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
proLogic "github.com/gravitl/netmaker/pro/logic"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
@ -101,7 +101,7 @@ func handleOIDCCallback(w http.ResponseWriter, r *http.Request) {
|
|||
if database.IsEmptyRecord(err) { // user must not exist, so try to make one
|
||||
if inviteExists {
|
||||
// create user
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fetchErr, "internal"))
|
||||
return
|
||||
|
@ -111,7 +111,7 @@ func handleOIDCCallback(w http.ResponseWriter, r *http.Request) {
|
|||
Password: newPass,
|
||||
}
|
||||
for _, inviteGroupID := range in.Groups {
|
||||
userG, err := logic.GetUserGroup(inviteGroupID)
|
||||
userG, err := proLogic.GetUserGroup(inviteGroupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("error fetching group id "+inviteGroupID.String()), "badrequest"))
|
||||
return
|
||||
|
@ -158,7 +158,7 @@ func handleOIDCCallback(w http.ResponseWriter, r *http.Request) {
|
|||
handleOauthUserNotAllowed(w)
|
||||
return
|
||||
}
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
var newPass, fetchErr = logic.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/auth"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/mq"
|
||||
"github.com/gravitl/netmaker/pro/auth"
|
||||
proAuth "github.com/gravitl/netmaker/pro/auth"
|
||||
"github.com/gravitl/netmaker/pro/email"
|
||||
proLogic "github.com/gravitl/netmaker/pro/logic"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
@ -21,10 +27,571 @@ func UserHandlers(r *mux.Router) {
|
|||
r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(removeUserFromRemoteAccessGW))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserRemoteAccessGwsV1)))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/users/ingress/{ingress_id}", logic.SecurityCheck(true, http.HandlerFunc(ingressGatewayUsers))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/oauth/headless", auth.HandleHeadlessSSO)
|
||||
r.HandleFunc("/api/oauth/register/{regKey}", auth.RegisterHostSSO).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/oauth/login", proAuth.HandleAuthLogin).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/oauth/callback", proAuth.HandleAuthCallback).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/oauth/headless", proAuth.HandleHeadlessSSO)
|
||||
r.HandleFunc("/api/oauth/register/{regKey}", proAuth.RegisterHostSSO).Methods(http.MethodGet)
|
||||
|
||||
// User Role Handlers
|
||||
r.HandleFunc("/api/v1/users/roles", logic.SecurityCheck(true, http.HandlerFunc(listRoles))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/role", getRole).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/role", logic.SecurityCheck(true, http.HandlerFunc(createRole))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/users/role", logic.SecurityCheck(true, http.HandlerFunc(updateRole))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/v1/users/role", logic.SecurityCheck(true, http.HandlerFunc(deleteRole))).Methods(http.MethodDelete)
|
||||
|
||||
// User Group Handlers
|
||||
r.HandleFunc("/api/v1/users/groups", logic.SecurityCheck(true, http.HandlerFunc(listUserGroups))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/group", logic.SecurityCheck(true, http.HandlerFunc(getUserGroup))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/group", logic.SecurityCheck(true, http.HandlerFunc(createUserGroup))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/users/group", logic.SecurityCheck(true, http.HandlerFunc(updateUserGroup))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/v1/users/group", logic.SecurityCheck(true, http.HandlerFunc(deleteUserGroup))).Methods(http.MethodDelete)
|
||||
|
||||
// User Invite Handlers
|
||||
r.HandleFunc("/api/v1/users/invite", userInviteVerify).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/invite-signup", userInviteSignUp).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/users/invite", logic.SecurityCheck(true, http.HandlerFunc(inviteUsers))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/users/invites", logic.SecurityCheck(true, http.HandlerFunc(listUserInvites))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/users/invite", logic.SecurityCheck(true, http.HandlerFunc(deleteUserInvite))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/v1/users/invites", logic.SecurityCheck(true, http.HandlerFunc(deleteAllUserInvites))).Methods(http.MethodDelete)
|
||||
|
||||
r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(getPendingUsers))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(deleteAllPendingUsers))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(deletePendingUser))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(approvePendingUser))).Methods(http.MethodPost)
|
||||
|
||||
}
|
||||
|
||||
// swagger:route POST /api/v1/users/invite-signup user userInviteSignUp
|
||||
//
|
||||
// user signup via invite.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponse
|
||||
func userInviteSignUp(w http.ResponseWriter, r *http.Request) {
|
||||
email, _ := url.QueryUnescape(r.URL.Query().Get("email"))
|
||||
code, _ := url.QueryUnescape(r.URL.Query().Get("invite_code"))
|
||||
in, err := logic.GetUserInvite(email)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
if code != in.InviteCode {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid invite code"), "badrequest"))
|
||||
return
|
||||
}
|
||||
// check if user already exists
|
||||
_, err = logic.GetUser(email)
|
||||
if err == nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user already exists"), "badrequest"))
|
||||
return
|
||||
}
|
||||
var user models.User
|
||||
err = json.NewDecoder(r.Body).Decode(&user)
|
||||
if err != nil {
|
||||
logger.Log(0, user.UserName, "error decoding request body: ",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
if user.UserName != email {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username not matching with invite"), "badrequest"))
|
||||
return
|
||||
}
|
||||
if user.Password == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("password cannot be empty"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, inviteGroupID := range in.Groups {
|
||||
userG, err := proLogic.GetUserGroup(inviteGroupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("error fetching group id "+inviteGroupID.String()), "badrequest"))
|
||||
return
|
||||
}
|
||||
user.PlatformRoleID = userG.PlatformRole
|
||||
user.UserGroups = make(map[models.UserGroupID]struct{})
|
||||
user.UserGroups[inviteGroupID] = struct{}{}
|
||||
}
|
||||
if user.PlatformRoleID == "" {
|
||||
user.PlatformRoleID = models.ServiceUser
|
||||
}
|
||||
user.NetworkRoles = make(map[models.NetworkID]map[models.UserRole]struct{})
|
||||
err = logic.CreateUser(&user)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
// delete invite
|
||||
logic.DeleteUserInvite(email)
|
||||
logic.DeletePendingUser(email)
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
logic.ReturnSuccessResponse(w, r, "created user successfully "+email)
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/users/invite user userInviteVerify
|
||||
//
|
||||
// verfies user invite.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponse
|
||||
func userInviteVerify(w http.ResponseWriter, r *http.Request) {
|
||||
email, _ := url.QueryUnescape(r.URL.Query().Get("email"))
|
||||
code, _ := url.QueryUnescape(r.URL.Query().Get("invite_code"))
|
||||
err := logic.ValidateAndApproveUserInvite(email, code)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "invite is valid")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/v1/users/invite user inviteUsers
|
||||
//
|
||||
// invite users.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func inviteUsers(w http.ResponseWriter, r *http.Request) {
|
||||
var inviteReq models.InviteUsersReq
|
||||
err := json.NewDecoder(r.Body).Decode(&inviteReq)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
//validate Req
|
||||
uniqueGroupsPlatformRole := make(map[models.UserRole]struct{})
|
||||
for _, groupID := range inviteReq.Groups {
|
||||
userG, err := proLogic.GetUserGroup(groupID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
uniqueGroupsPlatformRole[userG.PlatformRole] = struct{}{}
|
||||
}
|
||||
if len(uniqueGroupsPlatformRole) > 1 {
|
||||
err = errors.New("only groups with same platform role can be assigned to an user")
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, inviteeEmail := range inviteReq.UserEmails {
|
||||
// check if user with email exists, then ignore
|
||||
_, err := logic.GetUser(inviteeEmail)
|
||||
if err == nil {
|
||||
// user exists already, so ignore
|
||||
continue
|
||||
}
|
||||
invite := models.UserInvite{
|
||||
Email: inviteeEmail,
|
||||
Groups: inviteReq.Groups,
|
||||
InviteCode: logic.RandomString(8),
|
||||
}
|
||||
u, err := url.Parse(fmt.Sprintf("%s/invite?email=%s&invite_code=%s",
|
||||
servercfg.GetFrontendURL(), url.QueryEscape(invite.Email), url.QueryEscape(invite.InviteCode)))
|
||||
if err != nil {
|
||||
slog.Error("failed to parse to invite url", "error", err)
|
||||
return
|
||||
}
|
||||
invite.InviteURL = u.String()
|
||||
err = logic.InsertUserInvite(invite)
|
||||
if err != nil {
|
||||
slog.Error("failed to insert invite for user", "email", invite.Email, "error", err)
|
||||
}
|
||||
// notify user with magic link
|
||||
go func(invite models.UserInvite) {
|
||||
// Set E-Mail body. You can set plain text or html with text/html
|
||||
|
||||
e := email.UserInvitedMail{
|
||||
BodyBuilder: &email.EmailBodyBuilderWithH1HeadlineAndImage{},
|
||||
InviteURL: invite.InviteURL,
|
||||
}
|
||||
n := email.Notification{
|
||||
RecipientMail: invite.Email,
|
||||
}
|
||||
err = email.GetClient().SendEmail(context.Background(), n, e)
|
||||
if err != nil {
|
||||
slog.Error("failed to send email invite", "user", invite.Email, "error", err)
|
||||
}
|
||||
}(invite)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/users/invites user listUserInvites
|
||||
//
|
||||
// lists all pending invited users.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponseWithJson
|
||||
func listUserInvites(w http.ResponseWriter, r *http.Request) {
|
||||
usersInvites, err := logic.ListUserInvites()
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, usersInvites, "fetched pending user invites")
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/v1/users/invite user deleteUserInvite
|
||||
//
|
||||
// delete pending invite.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponse
|
||||
func deleteUserInvite(w http.ResponseWriter, r *http.Request) {
|
||||
email, _ := url.QueryUnescape(r.URL.Query().Get("invitee_email"))
|
||||
err := logic.DeleteUserInvite(email)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to delete user invite: ", email, err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "deleted user invite")
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/v1/users/invites user deleteAllUserInvites
|
||||
//
|
||||
// deletes all pending invites.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: ReturnSuccessResponse
|
||||
func deleteAllUserInvites(w http.ResponseWriter, r *http.Request) {
|
||||
err := database.DeleteAllRecords(database.USER_INVITES_TABLE_NAME)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to delete all pending user invites "+err.Error()), "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "cleared all pending user invites")
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/user/groups user listUserGroups
|
||||
//
|
||||
// Get all user groups.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func listUserGroups(w http.ResponseWriter, r *http.Request) {
|
||||
groups, err := proLogic.ListUserGroups()
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, groups, "successfully fetched user groups")
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/user/group user getUserGroup
|
||||
//
|
||||
// Get user group.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func getUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
gid, _ := url.QueryUnescape(r.URL.Query().Get("group_id"))
|
||||
if gid == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("group id is required"), "badrequest"))
|
||||
return
|
||||
}
|
||||
group, err := proLogic.GetUserGroup(models.UserGroupID(gid))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, group, "successfully fetched user group")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/v1/user/group user createUserGroup
|
||||
//
|
||||
// Create user groups.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func createUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
var userGroupReq models.CreateGroupReq
|
||||
err := json.NewDecoder(r.Body).Decode(&userGroupReq)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = proLogic.ValidateCreateGroupReq(userGroupReq.Group)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = proLogic.CreateUserGroup(userGroupReq.Group)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
for _, userID := range userGroupReq.Members {
|
||||
user, err := logic.GetUser(userID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if len(user.UserGroups) == 0 {
|
||||
user.UserGroups = make(map[models.UserGroupID]struct{})
|
||||
}
|
||||
user.UserGroups[userGroupReq.Group.ID] = struct{}{}
|
||||
logic.UpsertUser(*user)
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userGroupReq.Group, "created user group")
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/v1/user/group user updateUserGroup
|
||||
//
|
||||
// Update user group.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func updateUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
var userGroup models.UserGroup
|
||||
err := json.NewDecoder(r.Body).Decode(&userGroup)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = proLogic.ValidateUpdateGroupReq(userGroup)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = proLogic.UpdateUserGroup(userGroup)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userGroup, "updated user group")
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/v1/user/group user deleteUserGroup
|
||||
//
|
||||
// delete user group.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func deleteUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
gid, _ := url.QueryUnescape(r.URL.Query().Get("group_id"))
|
||||
if gid == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
|
||||
return
|
||||
}
|
||||
err := proLogic.DeleteUserGroup(models.UserGroupID(gid))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, nil, "deleted user group")
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/user/roles user listRoles
|
||||
//
|
||||
// lists all user roles.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func listRoles(w http.ResponseWriter, r *http.Request) {
|
||||
roles, err := proLogic.ListRoles()
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, roles, "successfully fetched user roles permission templates")
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/user/role user getRole
|
||||
//
|
||||
// Get user role permission templates.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func getRole(w http.ResponseWriter, r *http.Request) {
|
||||
rid, _ := url.QueryUnescape(r.URL.Query().Get("role_id"))
|
||||
if rid == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
|
||||
return
|
||||
}
|
||||
role, err := logic.GetRole(models.UserRole(rid))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, role, "successfully fetched user role permission templates")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/v1/user/role user createRole
|
||||
//
|
||||
// Create user role permission template.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func createRole(w http.ResponseWriter, r *http.Request) {
|
||||
var userRole models.UserRolePermissionTemplate
|
||||
err := json.NewDecoder(r.Body).Decode(&userRole)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = proLogic.ValidateCreateRoleReq(userRole)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
userRole.Default = false
|
||||
userRole.GlobalLevelAccess = make(map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope)
|
||||
err = proLogic.CreateRole(userRole)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userRole, "created user role")
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/v1/user/role user updateRole
|
||||
//
|
||||
// Update user role permission template.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func updateRole(w http.ResponseWriter, r *http.Request) {
|
||||
var userRole models.UserRolePermissionTemplate
|
||||
err := json.NewDecoder(r.Body).Decode(&userRole)
|
||||
if err != nil {
|
||||
slog.Error("error decoding request body", "error",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = proLogic.ValidateUpdateRoleReq(userRole)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
userRole.GlobalLevelAccess = make(map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope)
|
||||
err = proLogic.UpdateRole(userRole)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userRole, "updated user role")
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/v1/user/role user deleteRole
|
||||
//
|
||||
// Delete user role permission template.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func deleteRole(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
rid, _ := url.QueryUnescape(r.URL.Query().Get("role_id"))
|
||||
if rid == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
|
||||
return
|
||||
}
|
||||
err := proLogic.DeleteRole(models.UserRole(rid))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponseWithJson(w, r, nil, "created user role")
|
||||
}
|
||||
|
||||
// swagger:route POST /api/users/{username}/remote_access_gw user attachUserToRemoteAccessGateway
|
||||
|
@ -190,7 +757,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
logger.Log(0, "------------> 6. getUserRemoteAccessGwsV1")
|
||||
userGwNodes := logic.GetUserRAGNodes(*user)
|
||||
userGwNodes := proLogic.GetUserRAGNodes(*user)
|
||||
logger.Log(0, fmt.Sprintf("1. User Gw Nodes: %+v", userGwNodes))
|
||||
for _, extClient := range allextClients {
|
||||
node, ok := userGwNodes[extClient.IngressGatewayID]
|
||||
|
@ -528,3 +1095,135 @@ func getAllowedRagEndpoints(ragNode *models.Node, ragHost *models.Host) []string
|
|||
}
|
||||
return endpoints
|
||||
}
|
||||
|
||||
// swagger:route GET /api/users_pending user getPendingUsers
|
||||
//
|
||||
// Get all pending users.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func getPendingUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
users, err := logic.ListPendingUsers()
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
logic.SortUsers(users[:])
|
||||
logger.Log(2, r.Header.Get("user"), "fetched pending users")
|
||||
json.NewEncoder(w).Encode(users)
|
||||
}
|
||||
|
||||
// swagger:route POST /api/users_pending/user/{username} user approvePendingUser
|
||||
//
|
||||
// approve pending user.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func approvePendingUser(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
username := params["username"]
|
||||
users, err := logic.ListPendingUsers()
|
||||
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
for _, user := range users {
|
||||
if user.UserName == username {
|
||||
var newPass, fetchErr = auth.FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fetchErr, "internal"))
|
||||
return
|
||||
}
|
||||
if err = logic.CreateUser(&models.User{
|
||||
UserName: user.UserName,
|
||||
Password: newPass,
|
||||
}); err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to create user: %s", err), "internal"))
|
||||
return
|
||||
}
|
||||
err = logic.DeletePendingUser(username)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal"))
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "approved "+username)
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/users_pending/user/{username} user deletePendingUser
|
||||
//
|
||||
// delete pending user.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func deletePendingUser(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
username := params["username"]
|
||||
users, err := logic.ListPendingUsers()
|
||||
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to fetch users: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
for _, user := range users {
|
||||
if user.UserName == username {
|
||||
err = logic.DeletePendingUser(username)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal"))
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "deleted pending "+username)
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/users_pending/{username}/pending user deleteAllPendingUsers
|
||||
//
|
||||
// delete all pending users.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func deleteAllPendingUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
err := database.DeleteAllRecords(database.PENDING_USERS_TABLE_NAME)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to delete all pending users "+err.Error()), "internal"))
|
||||
return
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "cleared all pending users")
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
func InitPro() {
|
||||
servercfg.IsPro = true
|
||||
models.SetLogo(retrieveProLogo())
|
||||
proLogic.UserRolesInit()
|
||||
controller.HttpMiddlewares = append(
|
||||
controller.HttpMiddlewares,
|
||||
proControllers.OnlyServerAPIWhenUnlicensedMiddleware,
|
||||
|
@ -119,6 +120,15 @@ func InitPro() {
|
|||
logic.GetAllowedIpForInetNodeClient = proLogic.GetAllowedIpForInetNodeClient
|
||||
mq.UpdateMetrics = proLogic.MQUpdateMetrics
|
||||
mq.UpdateMetricsFallBack = proLogic.MQUpdateMetricsFallBack
|
||||
logic.GetFilteredNodesByUserAccess = proLogic.GetFilteredNodesByUserAccess
|
||||
logic.CreateRole = proLogic.CreateRole
|
||||
logic.NetworkPermissionsCheck = proLogic.NetworkPermissionsCheck
|
||||
logic.GlobalPermissionsCheck = proLogic.GlobalPermissionsCheck
|
||||
logic.DeleteNetworkRoles = proLogic.DeleteNetworkRoles
|
||||
logic.CreateDefaultNetworkRoles = proLogic.CreateDefaultNetworkRoles
|
||||
logic.FilterNetworksByRole = proLogic.FilterNetworksByRole
|
||||
logic.IsGroupsValid = proLogic.IsGroupsValid
|
||||
logic.RemoveNetworkRoleFromUsers = proLogic.RemoveNetworkRoleFromUsers
|
||||
}
|
||||
|
||||
func retrieveProLogo() string {
|
||||
|
|
186
pro/logic/security.go
Normal file
186
pro/logic/security.go
Normal file
|
@ -0,0 +1,186 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
func NetworkPermissionsCheck(username string, r *http.Request) error {
|
||||
// at this point global checks should be completed
|
||||
user, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 1")
|
||||
userRole, err := logic.GetRole(user.PlatformRoleID)
|
||||
if err != nil {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
if userRole.FullAccess {
|
||||
return nil
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 2")
|
||||
// get info from header to determine the target rsrc
|
||||
targetRsrc := r.Header.Get("TARGET_RSRC")
|
||||
targetRsrcID := r.Header.Get("TARGET_RSRC_ID")
|
||||
netID := r.Header.Get("NET_ID")
|
||||
if targetRsrc == "" {
|
||||
return errors.New("target rsrc is missing")
|
||||
}
|
||||
if netID == "" {
|
||||
return errors.New("network id is missing")
|
||||
}
|
||||
if r.Method == "" {
|
||||
r.Method = http.MethodGet
|
||||
}
|
||||
if targetRsrc == models.MetricRsrc.String() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check if user has scope for target resource
|
||||
// TODO - differentitate between global scope and network scope apis
|
||||
netRoles := user.NetworkRoles[models.NetworkID(netID)]
|
||||
for netRoleID := range netRoles {
|
||||
err = checkNetworkAccessPermissions(netRoleID, username, r.Method, targetRsrc, targetRsrcID)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for groupID := range user.UserGroups {
|
||||
userG, err := GetUserGroup(groupID)
|
||||
if err == nil {
|
||||
netRoles := userG.NetworkRoles[models.NetworkID(netID)]
|
||||
for netRoleID := range netRoles {
|
||||
err = checkNetworkAccessPermissions(netRoleID, username, r.Method, targetRsrc, targetRsrcID)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("access denied")
|
||||
}
|
||||
|
||||
func checkNetworkAccessPermissions(netRoleID models.UserRole, username, reqScope, targetRsrc, targetRsrcID string) error {
|
||||
networkPermissionScope, err := logic.GetRole(netRoleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 3", string(netRoleID))
|
||||
if networkPermissionScope.FullAccess {
|
||||
return nil
|
||||
}
|
||||
rsrcPermissionScope, ok := networkPermissionScope.NetworkLevelAccess[models.RsrcType(targetRsrc)]
|
||||
if targetRsrc == models.HostRsrc.String() && !ok {
|
||||
rsrcPermissionScope, ok = networkPermissionScope.NetworkLevelAccess[models.RemoteAccessGwRsrc]
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 4", string(netRoleID))
|
||||
if allRsrcsTypePermissionScope, ok := rsrcPermissionScope[models.RsrcID(fmt.Sprintf("all_%s", targetRsrc))]; ok {
|
||||
// handle extclient apis here
|
||||
if models.RsrcType(targetRsrc) == models.ExtClientsRsrc && allRsrcsTypePermissionScope.SelfOnly && targetRsrcID != "" {
|
||||
extclient, err := logic.GetExtClient(targetRsrcID, networkPermissionScope.NetworkID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !logic.IsUserAllowedAccessToExtClient(username, extclient) {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
}
|
||||
err = checkPermissionScopeWithReqMethod(allRsrcsTypePermissionScope, reqScope)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
if targetRsrc == models.HostRsrc.String() {
|
||||
if allRsrcsTypePermissionScope, ok := rsrcPermissionScope[models.RsrcID(fmt.Sprintf("all_%s", models.RemoteAccessGwRsrc))]; ok {
|
||||
err = checkPermissionScopeWithReqMethod(allRsrcsTypePermissionScope, reqScope)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 5", string(netRoleID))
|
||||
if targetRsrcID == "" {
|
||||
return errors.New("target rsrc id is empty")
|
||||
}
|
||||
if scope, ok := rsrcPermissionScope[models.RsrcID(targetRsrcID)]; ok {
|
||||
err = checkPermissionScopeWithReqMethod(scope, reqScope)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
logger.Log(0, "NET MIDDL----> 6", string(netRoleID))
|
||||
return errors.New("access denied")
|
||||
}
|
||||
|
||||
func GlobalPermissionsCheck(username string, r *http.Request) error {
|
||||
user, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userRole, err := logic.GetRole(user.PlatformRoleID)
|
||||
if err != nil {
|
||||
return errors.New("access denied")
|
||||
}
|
||||
if userRole.FullAccess {
|
||||
return nil
|
||||
}
|
||||
targetRsrc := r.Header.Get("TARGET_RSRC")
|
||||
targetRsrcID := r.Header.Get("TARGET_RSRC_ID")
|
||||
if targetRsrc == "" {
|
||||
return errors.New("target rsrc is missing")
|
||||
}
|
||||
if r.Method == "" {
|
||||
r.Method = http.MethodGet
|
||||
}
|
||||
if targetRsrc == models.MetricRsrc.String() {
|
||||
return nil
|
||||
}
|
||||
if (targetRsrc == models.HostRsrc.String() || targetRsrc == models.NetworkRsrc.String()) && r.Method == http.MethodGet && targetRsrcID == "" {
|
||||
return nil
|
||||
}
|
||||
if targetRsrc == models.UserRsrc.String() && username == targetRsrcID && (r.Method != http.MethodDelete) {
|
||||
return nil
|
||||
}
|
||||
rsrcPermissionScope, ok := userRole.GlobalLevelAccess[models.RsrcType(targetRsrc)]
|
||||
if !ok {
|
||||
return fmt.Errorf("access denied to %s rsrc", targetRsrc)
|
||||
}
|
||||
if allRsrcsTypePermissionScope, ok := rsrcPermissionScope[models.RsrcID(fmt.Sprintf("all_%s", targetRsrc))]; ok {
|
||||
return checkPermissionScopeWithReqMethod(allRsrcsTypePermissionScope, r.Method)
|
||||
|
||||
}
|
||||
if targetRsrcID == "" {
|
||||
return errors.New("target rsrc id is missing")
|
||||
}
|
||||
if scope, ok := rsrcPermissionScope[models.RsrcID(targetRsrcID)]; ok {
|
||||
return checkPermissionScopeWithReqMethod(scope, r.Method)
|
||||
}
|
||||
return errors.New("access denied")
|
||||
}
|
||||
|
||||
func checkPermissionScopeWithReqMethod(scope models.RsrcPermissionScope, reqmethod string) error {
|
||||
if reqmethod == http.MethodGet && scope.Read {
|
||||
return nil
|
||||
}
|
||||
if (reqmethod == http.MethodPatch || reqmethod == http.MethodPut) && scope.Update {
|
||||
return nil
|
||||
}
|
||||
if reqmethod == http.MethodDelete && scope.Delete {
|
||||
return nil
|
||||
}
|
||||
if reqmethod == http.MethodPost && scope.Create {
|
||||
return nil
|
||||
}
|
||||
return errors.New("operation not permitted")
|
||||
}
|
620
pro/logic/user_mgmt.go
Normal file
620
pro/logic/user_mgmt.go
Normal file
|
@ -0,0 +1,620 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
var ServiceUserPermissionTemplate = models.UserRolePermissionTemplate{
|
||||
ID: models.ServiceUser,
|
||||
Default: true,
|
||||
FullAccess: false,
|
||||
DenyDashboardAccess: true,
|
||||
}
|
||||
|
||||
var PlatformUserUserPermissionTemplate = models.UserRolePermissionTemplate{
|
||||
ID: models.PlatformUser,
|
||||
Default: true,
|
||||
FullAccess: false,
|
||||
}
|
||||
|
||||
func UserRolesInit() {
|
||||
d, _ := json.Marshal(ServiceUserPermissionTemplate)
|
||||
database.Insert(ServiceUserPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
d, _ = json.Marshal(PlatformUserUserPermissionTemplate)
|
||||
database.Insert(PlatformUserUserPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
|
||||
}
|
||||
|
||||
func CreateDefaultNetworkRoles(netID string) {
|
||||
var NetworkAdminPermissionTemplate = models.UserRolePermissionTemplate{
|
||||
ID: models.UserRole(fmt.Sprintf("%s_%s", netID, models.NetworkAdmin)),
|
||||
Default: false,
|
||||
NetworkID: netID,
|
||||
FullAccess: true,
|
||||
NetworkLevelAccess: make(map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope),
|
||||
}
|
||||
|
||||
var NetworkUserPermissionTemplate = models.UserRolePermissionTemplate{
|
||||
ID: models.UserRole(fmt.Sprintf("%s_%s", netID, models.NetworkUser)),
|
||||
Default: false,
|
||||
FullAccess: false,
|
||||
NetworkID: netID,
|
||||
DenyDashboardAccess: false,
|
||||
NetworkLevelAccess: map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope{
|
||||
models.RemoteAccessGwRsrc: {
|
||||
models.AllRemoteAccessGwRsrcID: models.RsrcPermissionScope{
|
||||
Read: true,
|
||||
VPNaccess: true,
|
||||
},
|
||||
},
|
||||
models.ExtClientsRsrc: {
|
||||
models.AllExtClientsRsrcID: models.RsrcPermissionScope{
|
||||
Read: true,
|
||||
Create: true,
|
||||
Update: true,
|
||||
Delete: true,
|
||||
SelfOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
d, _ := json.Marshal(NetworkAdminPermissionTemplate)
|
||||
database.Insert(NetworkAdminPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
d, _ = json.Marshal(NetworkUserPermissionTemplate)
|
||||
database.Insert(NetworkUserPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
}
|
||||
|
||||
func DeleteNetworkRoles(netID string) {
|
||||
users, err := logic.GetUsersDB()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, user := range users {
|
||||
if _, ok := user.NetworkRoles[models.NetworkID(netID)]; ok {
|
||||
delete(user.NetworkRoles, models.NetworkID(netID))
|
||||
logic.UpsertUser(user)
|
||||
}
|
||||
|
||||
}
|
||||
userGs, _ := ListUserGroups()
|
||||
for _, userGI := range userGs {
|
||||
if _, ok := userGI.NetworkRoles[models.NetworkID(netID)]; ok {
|
||||
delete(userGI.NetworkRoles, models.NetworkID(netID))
|
||||
UpdateUserGroup(userGI)
|
||||
}
|
||||
}
|
||||
|
||||
roles, _ := ListRoles()
|
||||
for _, role := range roles {
|
||||
if role.NetworkID == netID {
|
||||
DeleteRole(role.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ListRoles - lists user roles permission templates
|
||||
func ListRoles() ([]models.UserRolePermissionTemplate, error) {
|
||||
data, err := database.FetchRecords(database.USER_PERMISSIONS_TABLE_NAME)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return []models.UserRolePermissionTemplate{}, err
|
||||
}
|
||||
userRoles := []models.UserRolePermissionTemplate{}
|
||||
for _, dataI := range data {
|
||||
userRole := models.UserRolePermissionTemplate{}
|
||||
err := json.Unmarshal([]byte(dataI), &userRole)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
userRoles = append(userRoles, userRole)
|
||||
}
|
||||
return userRoles, nil
|
||||
}
|
||||
|
||||
func ValidateCreateRoleReq(userRole models.UserRolePermissionTemplate) error {
|
||||
// check if role exists with this id
|
||||
_, err := logic.GetRole(userRole.ID)
|
||||
if err == nil {
|
||||
return fmt.Errorf("role with id `%s` exists already", userRole.ID.String())
|
||||
}
|
||||
if len(userRole.NetworkLevelAccess) > 0 {
|
||||
for rsrcType := range userRole.NetworkLevelAccess {
|
||||
if _, ok := models.RsrcTypeMap[rsrcType]; !ok {
|
||||
return errors.New("invalid rsrc type " + rsrcType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
if userRole.NetworkID == "" {
|
||||
return errors.New("only network roles are allowed to be created")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateUpdateRoleReq(userRole models.UserRolePermissionTemplate) error {
|
||||
roleInDB, err := logic.GetRole(userRole.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if roleInDB.NetworkID != userRole.NetworkID {
|
||||
return errors.New("network id mismatch")
|
||||
}
|
||||
if roleInDB.Default {
|
||||
return errors.New("cannot update default role")
|
||||
}
|
||||
if len(userRole.NetworkLevelAccess) > 0 {
|
||||
for rsrcType := range userRole.NetworkLevelAccess {
|
||||
if _, ok := models.RsrcTypeMap[rsrcType]; !ok {
|
||||
return errors.New("invalid rsrc type " + rsrcType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateRole - inserts new role into DB
|
||||
func CreateRole(r models.UserRolePermissionTemplate) error {
|
||||
// check if role already exists
|
||||
if r.ID.String() == "" {
|
||||
return errors.New("role id cannot be empty")
|
||||
}
|
||||
_, err := database.FetchRecord(database.USER_PERMISSIONS_TABLE_NAME, r.ID.String())
|
||||
if err == nil {
|
||||
return errors.New("role already exists")
|
||||
}
|
||||
d, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(r.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// UpdateRole - updates role template
|
||||
func UpdateRole(r models.UserRolePermissionTemplate) error {
|
||||
if r.ID.String() == "" {
|
||||
return errors.New("role id cannot be empty")
|
||||
}
|
||||
_, err := database.FetchRecord(database.USER_PERMISSIONS_TABLE_NAME, r.ID.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(r.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// DeleteRole - deletes user role
|
||||
func DeleteRole(rid models.UserRole) error {
|
||||
if rid.String() == "" {
|
||||
return errors.New("role id cannot be empty")
|
||||
}
|
||||
users, err := logic.GetUsersDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role, err := logic.GetRole(rid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if role.Default {
|
||||
return errors.New("cannot delete default role")
|
||||
}
|
||||
for _, user := range users {
|
||||
for userG := range user.UserGroups {
|
||||
ug, err := GetUserGroup(userG)
|
||||
if err == nil {
|
||||
if role.NetworkID != "" {
|
||||
for _, networkRoles := range ug.NetworkRoles {
|
||||
if _, ok := networkRoles[rid]; ok {
|
||||
err = errors.New("role cannot be deleted as active user groups are using this role")
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if user.PlatformRoleID == rid {
|
||||
err = errors.New("active roles cannot be deleted.switch existing users to a new role before deleting")
|
||||
return err
|
||||
}
|
||||
for _, networkRoles := range user.NetworkRoles {
|
||||
if _, ok := networkRoles[rid]; ok {
|
||||
err = errors.New("active roles cannot be deleted.switch existing users to a new role before deleting")
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return database.DeleteRecord(database.USER_PERMISSIONS_TABLE_NAME, rid.String())
|
||||
}
|
||||
|
||||
func ValidateCreateGroupReq(g models.UserGroup) error {
|
||||
// check platform role is valid
|
||||
role, err := logic.GetRole(g.PlatformRole)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid platform role")
|
||||
return err
|
||||
}
|
||||
if role.NetworkID != "" {
|
||||
return errors.New("network role cannot be used as platform role")
|
||||
}
|
||||
// check if network roles are valid
|
||||
for _, roleMap := range g.NetworkRoles {
|
||||
for roleID := range roleMap {
|
||||
role, err := logic.GetRole(roleID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid network role %s", roleID)
|
||||
}
|
||||
if role.NetworkID == "" {
|
||||
return errors.New("platform role cannot be used as network role")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func ValidateUpdateGroupReq(g models.UserGroup) error {
|
||||
// check platform role is valid
|
||||
role, err := logic.GetRole(g.PlatformRole)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid platform role")
|
||||
return err
|
||||
}
|
||||
if role.NetworkID != "" {
|
||||
return errors.New("network role cannot be used as platform role")
|
||||
}
|
||||
for networkID := range g.NetworkRoles {
|
||||
userRolesMap := g.NetworkRoles[networkID]
|
||||
for roleID := range userRolesMap {
|
||||
netRole, err := logic.GetRole(roleID)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid network role")
|
||||
return err
|
||||
}
|
||||
if netRole.NetworkID == "" {
|
||||
return errors.New("platform role cannot be used as network role")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateUserGroup - creates new user group
|
||||
func CreateUserGroup(g models.UserGroup) error {
|
||||
// check if role already exists
|
||||
if g.ID == "" {
|
||||
return errors.New("group id cannot be empty")
|
||||
}
|
||||
_, err := database.FetchRecord(database.USER_GROUPS_TABLE_NAME, g.ID.String())
|
||||
if err == nil {
|
||||
return errors.New("group already exists")
|
||||
}
|
||||
d, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(g.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// GetUserGroup - fetches user group
|
||||
func GetUserGroup(gid models.UserGroupID) (models.UserGroup, error) {
|
||||
d, err := database.FetchRecord(database.USER_GROUPS_TABLE_NAME, gid.String())
|
||||
if err != nil {
|
||||
return models.UserGroup{}, err
|
||||
}
|
||||
var ug models.UserGroup
|
||||
err = json.Unmarshal([]byte(d), &ug)
|
||||
if err != nil {
|
||||
return ug, err
|
||||
}
|
||||
return ug, nil
|
||||
}
|
||||
|
||||
// ListUserGroups - lists user groups
|
||||
func ListUserGroups() ([]models.UserGroup, error) {
|
||||
data, err := database.FetchRecords(database.USER_GROUPS_TABLE_NAME)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return []models.UserGroup{}, err
|
||||
}
|
||||
userGroups := []models.UserGroup{}
|
||||
for _, dataI := range data {
|
||||
userGroup := models.UserGroup{}
|
||||
err := json.Unmarshal([]byte(dataI), &userGroup)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
userGroups = append(userGroups, userGroup)
|
||||
}
|
||||
return userGroups, nil
|
||||
}
|
||||
|
||||
// UpdateUserGroup - updates new user group
|
||||
func UpdateUserGroup(g models.UserGroup) error {
|
||||
// check if group exists
|
||||
if g.ID == "" {
|
||||
return errors.New("group id cannot be empty")
|
||||
}
|
||||
_, err := database.FetchRecord(database.USER_GROUPS_TABLE_NAME, g.ID.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(g.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// DeleteUserGroup - deletes user group
|
||||
func DeleteUserGroup(gid models.UserGroupID) error {
|
||||
users, err := logic.GetUsersDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range users {
|
||||
delete(user.UserGroups, gid)
|
||||
logic.UpsertUser(user)
|
||||
}
|
||||
return database.DeleteRecord(database.USER_GROUPS_TABLE_NAME, gid.String())
|
||||
}
|
||||
|
||||
func HasNetworkRsrcScope(permissionTemplate models.UserRolePermissionTemplate, netid string, rsrcType models.RsrcType, rsrcID models.RsrcID, op string) bool {
|
||||
if permissionTemplate.FullAccess {
|
||||
return true
|
||||
}
|
||||
|
||||
rsrcScope, ok := permissionTemplate.NetworkLevelAccess[rsrcType]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_, ok = rsrcScope[rsrcID]
|
||||
return ok
|
||||
}
|
||||
func GetUserRAGNodes(user models.User) (gws map[string]models.Node) {
|
||||
logger.Log(0, "------------> 7. getUserRemoteAccessGwsV1")
|
||||
gws = make(map[string]models.Node)
|
||||
userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user)
|
||||
logger.Log(0, fmt.Sprintf("User Gw Access Scope: %+v", userGwAccessScope))
|
||||
_, allNetAccess := userGwAccessScope["*"]
|
||||
nodes, err := logic.GetAllNodes()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
logger.Log(0, "------------> 8. getUserRemoteAccessGwsV1")
|
||||
for _, node := range nodes {
|
||||
if node.IsIngressGateway && !node.PendingDelete {
|
||||
if allNetAccess {
|
||||
gws[node.ID.String()] = node
|
||||
} else {
|
||||
gwRsrcMap := userGwAccessScope[models.NetworkID(node.Network)]
|
||||
scope, ok := gwRsrcMap[models.AllRemoteAccessGwRsrcID]
|
||||
if !ok {
|
||||
if scope, ok = gwRsrcMap[models.RsrcID(node.ID.String())]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if scope.VPNaccess {
|
||||
gws[node.ID.String()] = node
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Log(0, "------------> 9. getUserRemoteAccessGwsV1")
|
||||
return
|
||||
}
|
||||
|
||||
// GetUserNetworkRoles - get user network roles
|
||||
func GetUserNetworkRolesWithRemoteVPNAccess(user models.User) (gwAccess map[models.NetworkID]map[models.RsrcID]models.RsrcPermissionScope) {
|
||||
gwAccess = make(map[models.NetworkID]map[models.RsrcID]models.RsrcPermissionScope)
|
||||
logger.Log(0, "------------> 7.1 getUserRemoteAccessGwsV1")
|
||||
platformRole, err := logic.GetRole(user.PlatformRoleID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if platformRole.FullAccess {
|
||||
gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope)
|
||||
return
|
||||
}
|
||||
logger.Log(0, "------------> 7.2 getUserRemoteAccessGwsV1")
|
||||
for netID, roleMap := range user.NetworkRoles {
|
||||
for roleID := range roleMap {
|
||||
role, err := logic.GetRole(roleID)
|
||||
if err == nil {
|
||||
if role.FullAccess {
|
||||
gwAccess[netID] = map[models.RsrcID]models.RsrcPermissionScope{
|
||||
models.AllRemoteAccessGwRsrcID: {
|
||||
Create: true,
|
||||
Read: true,
|
||||
Update: true,
|
||||
VPNaccess: true,
|
||||
Delete: true,
|
||||
},
|
||||
models.AllExtClientsRsrcID: {
|
||||
Create: true,
|
||||
Read: true,
|
||||
Update: true,
|
||||
Delete: true,
|
||||
},
|
||||
}
|
||||
break
|
||||
}
|
||||
if rsrcsMap, ok := role.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok {
|
||||
if permissions, ok := rsrcsMap[models.AllRemoteAccessGwRsrcID]; ok && permissions.VPNaccess {
|
||||
if len(gwAccess[netID]) == 0 {
|
||||
gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope)
|
||||
}
|
||||
gwAccess[netID][models.AllRemoteAccessGwRsrcID] = permissions
|
||||
break
|
||||
} else {
|
||||
for gwID, scope := range rsrcsMap {
|
||||
if scope.VPNaccess {
|
||||
if len(gwAccess[netID]) == 0 {
|
||||
gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope)
|
||||
}
|
||||
gwAccess[netID][gwID] = scope
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Log(0, "------------> 7.3 getUserRemoteAccessGwsV1")
|
||||
return
|
||||
}
|
||||
|
||||
func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filteredNodes []models.Node) {
|
||||
|
||||
nodesMap := make(map[string]struct{})
|
||||
allNetworkRoles := []models.UserRole{}
|
||||
if len(user.NetworkRoles) > 0 {
|
||||
for _, netRoles := range user.NetworkRoles {
|
||||
for netRoleI := range netRoles {
|
||||
allNetworkRoles = append(allNetworkRoles, netRoleI)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(user.UserGroups) > 0 {
|
||||
for userGID := range user.UserGroups {
|
||||
userG, err := GetUserGroup(userGID)
|
||||
if err == nil {
|
||||
if len(userG.NetworkRoles) > 0 {
|
||||
for _, netRoles := range userG.NetworkRoles {
|
||||
for netRoleI := range netRoles {
|
||||
allNetworkRoles = append(allNetworkRoles, netRoleI)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, networkRoleID := range allNetworkRoles {
|
||||
userPermTemplate, err := logic.GetRole(networkRoleID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
networkNodes := logic.GetNetworkNodesMemory(nodes, userPermTemplate.NetworkID)
|
||||
if userPermTemplate.FullAccess {
|
||||
for _, node := range networkNodes {
|
||||
nodesMap[node.ID.String()] = struct{}{}
|
||||
}
|
||||
filteredNodes = append(filteredNodes, networkNodes...)
|
||||
continue
|
||||
}
|
||||
if rsrcPerms, ok := userPermTemplate.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok {
|
||||
if _, ok := rsrcPerms[models.AllRemoteAccessGwRsrcID]; ok {
|
||||
for _, node := range networkNodes {
|
||||
if _, ok := nodesMap[node.ID.String()]; ok {
|
||||
continue
|
||||
}
|
||||
if node.IsIngressGateway {
|
||||
nodesMap[node.ID.String()] = struct{}{}
|
||||
filteredNodes = append(filteredNodes, node)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for gwID, scope := range rsrcPerms {
|
||||
if _, ok := nodesMap[gwID.String()]; ok {
|
||||
continue
|
||||
}
|
||||
if scope.Read {
|
||||
gwNode, err := logic.GetNodeByID(gwID.String())
|
||||
if err == nil && gwNode.IsIngressGateway {
|
||||
filteredNodes = append(filteredNodes, gwNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func FilterNetworksByRole(allnetworks []models.Network, user models.User) []models.Network {
|
||||
platformRole, err := logic.GetRole(user.PlatformRoleID)
|
||||
if err != nil {
|
||||
return []models.Network{}
|
||||
}
|
||||
if !platformRole.FullAccess {
|
||||
allNetworkRoles := make(map[models.NetworkID]struct{})
|
||||
if len(user.NetworkRoles) > 0 {
|
||||
for netID := range user.NetworkRoles {
|
||||
allNetworkRoles[netID] = struct{}{}
|
||||
|
||||
}
|
||||
}
|
||||
if len(user.UserGroups) > 0 {
|
||||
for userGID := range user.UserGroups {
|
||||
userG, err := GetUserGroup(userGID)
|
||||
if err == nil {
|
||||
if len(userG.NetworkRoles) > 0 {
|
||||
for netID := range userG.NetworkRoles {
|
||||
allNetworkRoles[netID] = struct{}{}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
filteredNetworks := []models.Network{}
|
||||
for _, networkI := range allnetworks {
|
||||
if _, ok := allNetworkRoles[models.NetworkID(networkI.NetID)]; ok {
|
||||
filteredNetworks = append(filteredNetworks, networkI)
|
||||
}
|
||||
}
|
||||
allnetworks = filteredNetworks
|
||||
}
|
||||
return allnetworks
|
||||
}
|
||||
|
||||
func IsGroupsValid(groups map[models.UserGroupID]struct{}) error {
|
||||
uniqueGroupsPlatformRole := make(map[models.UserRole]struct{})
|
||||
for groupID := range groups {
|
||||
userG, err := GetUserGroup(groupID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uniqueGroupsPlatformRole[userG.PlatformRole] = struct{}{}
|
||||
}
|
||||
if len(uniqueGroupsPlatformRole) > 1 {
|
||||
|
||||
return errors.New("only groups with same platform role can be assigned to an user")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveNetworkRoleFromUsers(host models.Host, node models.Node) {
|
||||
users, err := logic.GetUsersDB()
|
||||
if err == nil {
|
||||
for _, user := range users {
|
||||
// delete role from user
|
||||
if netRoles, ok := user.NetworkRoles[models.NetworkID(node.Network)]; ok {
|
||||
delete(netRoles, models.GetRAGRoleName(node.Network, host.Name))
|
||||
user.NetworkRoles[models.NetworkID(node.Network)] = netRoles
|
||||
err = logic.UpsertUser(user)
|
||||
if err != nil {
|
||||
slog.Error("failed to get user", "user", user.UserName, "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
slog.Error("failed to get users", "error", err)
|
||||
}
|
||||
err = DeleteRole(models.GetRAGRoleName(node.Network, host.Name))
|
||||
if err != nil {
|
||||
slog.Error("failed to delete role: ", models.GetRAGRoleName(node.Network, host.Name), err)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue