Jelajahi Sumber

migrate rac apis to new user mgmt

abhishek9686 1 tahun lalu
induk
melakukan
9abc892c5a
6 mengubah file dengan 236 tambahan dan 44 penghapusan
  1. 1 35
      controllers/ext_client.go
  2. 2 1
      logic/auth.go
  3. 2 4
      logic/gateway.go
  4. 20 3
      logic/security.go
  5. 78 0
      logic/user_mgmt.go
  6. 133 1
      pro/controllers/users.go

+ 1 - 35
controllers/ext_client.go

@@ -133,14 +133,6 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-	if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) {
-		// check if user has access to extclient
-		slog.Error("failed to get extclient", "network", network, "clientID",
-			clientid, "error", errors.New("access is denied"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
-		return
-
-	}
 
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(client)
@@ -171,12 +163,6 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-	if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) {
-		slog.Error("failed to get extclient", "network", networkid, "clientID",
-			clientid, "error", errors.New("access is denied"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
-		return
-	}
 
 	gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
 	if err != nil {
@@ -414,12 +400,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 		userName = caller.UserName
-		if _, ok := caller.RemoteGwIDs[nodeid]; (caller.PlatformRoleID != models.AdminRole && caller.PlatformRoleID != models.SuperAdminRole) && !ok {
-			err = errors.New("permission denied")
-			slog.Error("failed to create extclient", "error", err)
-			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
-			return
-		}
 		// check if user has a config already for remote access client
 		extclients, err := logic.GetNetworkExtClients(node.Network)
 		if err != nil {
@@ -515,21 +495,12 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	clientid := params["clientid"]
-	network := params["network"]
 	oldExtClient, err := logic.GetExtClientByName(clientid)
 	if err != nil {
 		slog.Error("failed to retrieve extclient", "user", r.Header.Get("user"), "id", clientid, "error", err)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-	if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), oldExtClient) {
-		// check if user has access to extclient
-		slog.Error("failed to get extclient", "network", network, "clientID",
-			clientid, "error", errors.New("access is denied"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
-		return
-
-	}
 	if oldExtClient.ClientID == update.ClientID {
 		if err := validateCustomExtClient(&update, false); err != nil {
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
@@ -637,12 +608,7 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-	if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), extclient) {
-		slog.Error("user not allowed to delete", "network", network, "clientID",
-			clientid, "error", errors.New("access is denied"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
-		return
-	}
+
 	ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
 	if err != nil {
 		logger.Log(0, r.Header.Get("user"),

+ 2 - 1
logic/auth.go

@@ -239,7 +239,8 @@ func UpdateUser(userchange, user *models.User) (*models.User, error) {
 		user.Password = userchange.Password
 	}
 	user.PlatformRoleID = userchange.PlatformRoleID
-
+	user.UserGroups = userchange.UserGroups
+	user.NetworkRoles = userchange.NetworkRoles
 	err := ValidateUser(user)
 	if err != nil {
 		return &models.User{}, err

+ 2 - 4
logic/gateway.go

@@ -264,10 +264,8 @@ func IsUserAllowedAccessToExtClient(username string, client models.ExtClient) bo
 	if err != nil {
 		return false
 	}
-	if user.PlatformRoleID != models.AdminRole && user.PlatformRoleID != models.SuperAdminRole {
-		if user.UserName != client.OwnerID {
-			return false
-		}
+	if user.UserName != client.OwnerID {
+		return false
 	}
 	return true
 }

+ 20 - 3
logic/security.go

@@ -7,6 +7,7 @@ import (
 	"strings"
 
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/servercfg"
 )
@@ -34,6 +35,7 @@ func networkPermissionsCheck(username string, r *http.Request) error {
 	if err != nil {
 		return err
 	}
+	logger.Log(0, "NET MIDDL----> 1")
 	userRole, err := GetRole(user.PlatformRoleID)
 	if err != nil {
 		return errors.New("access denied")
@@ -41,6 +43,7 @@ func networkPermissionsCheck(username string, r *http.Request) error {
 	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")
@@ -61,7 +64,7 @@ func networkPermissionsCheck(username string, r *http.Request) error {
 	// TODO - differentitate between global scope and network scope apis
 	netRoles := user.NetworkRoles[models.NetworkID(netID)]
 	for netRoleID := range netRoles {
-		err = checkNetworkAccessPermissions(netRoleID, r.Method, targetRsrc, targetRsrcID)
+		err = checkNetworkAccessPermissions(netRoleID, username, r.Method, targetRsrc, targetRsrcID)
 		if err == nil {
 			return nil
 		}
@@ -71,7 +74,7 @@ func networkPermissionsCheck(username string, r *http.Request) error {
 		if err == nil {
 			netRoles := userG.NetworkRoles[models.NetworkID(netID)]
 			for netRoleID := range netRoles {
-				err = checkNetworkAccessPermissions(netRoleID, r.Method, targetRsrc, targetRsrcID)
+				err = checkNetworkAccessPermissions(netRoleID, username, r.Method, targetRsrc, targetRsrcID)
 				if err == nil {
 					return nil
 				}
@@ -82,11 +85,12 @@ func networkPermissionsCheck(username string, r *http.Request) error {
 	return errors.New("access denied")
 }
 
-func checkNetworkAccessPermissions(netRoleID models.UserRole, reqScope, targetRsrc, targetRsrcID string) error {
+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
 	}
@@ -94,13 +98,25 @@ func checkNetworkAccessPermissions(netRoleID models.UserRole, reqScope, targetRs
 	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
 		}
 
 	}
+	logger.Log(0, "NET MIDDL----> 5", string(netRoleID))
 	if targetRsrcID == "" {
 		return errors.New("target rsrc id is empty")
 	}
@@ -110,6 +126,7 @@ func checkNetworkAccessPermissions(netRoleID models.UserRole, reqScope, targetRs
 			return nil
 		}
 	}
+	logger.Log(0, "NET MIDDL----> 6", string(netRoleID))
 	return errors.New("access denied")
 }
 

+ 78 - 0
logic/user_mgmt.go

@@ -374,3 +374,81 @@ func HasNetworkRsrcScope(permissionTemplate models.UserRolePermissionTemplate, n
 	_, ok = rsrcScope[rsrcID]
 	return ok
 }
+func GetUserRAGNodes(user models.User) (gws map[string]models.Node) {
+	gws = make(map[string]models.Node)
+	userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user)
+	_, allNetAccess := userGwAccessScope["*"]
+	nodes, err := GetAllNodes()
+	if err != nil {
+		return
+	}
+	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 _, ok := gwRsrcMap[models.RsrcID(node.ID.String())]; !ok {
+						continue
+					}
+				}
+				if scope.VPNaccess {
+					gws[node.ID.String()] = node
+				}
+
+			}
+		}
+	}
+	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)
+	platformRole, err := GetRole(user.PlatformRoleID)
+	if err != nil {
+		return
+	}
+	if platformRole.FullAccess {
+		gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope)
+		return
+	}
+	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,
+							VPNaccess: 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 {
+								gwAccess[netID][gwID] = scope
+							}
+						}
+					}
+
+				}
+
+			}
+		}
+	}
+	return
+}

+ 133 - 1
pro/controllers/users.go

@@ -19,7 +19,7 @@ import (
 func UserHandlers(r *mux.Router) {
 	r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(attachUserToRemoteAccessGw))).Methods(http.MethodPost)
 	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(getUserRemoteAccessGws)))).Methods(http.MethodGet)
+	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)
@@ -145,6 +145,138 @@ func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
 }
 
+func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) {
+	// set header.
+	w.Header().Set("Content-Type", "application/json")
+
+	var params = mux.Vars(r)
+	username := params["username"]
+	if username == "" {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params username"), "badrequest"))
+		return
+	}
+	user, err := logic.GetUser(username)
+	if err != nil {
+		logger.Log(0, username, "failed to fetch user: ", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest"))
+		return
+	}
+	remoteAccessClientID := r.URL.Query().Get("remote_access_clientid")
+	var req models.UserRemoteGwsReq
+	if remoteAccessClientID == "" {
+		err := json.NewDecoder(r.Body).Decode(&req)
+		if err != nil {
+			slog.Error("error decoding request body: ", "error", err)
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+			return
+		}
+	}
+	reqFromMobile := r.URL.Query().Get("from_mobile") == "true"
+	if req.RemoteAccessClientID == "" && remoteAccessClientID == "" {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("remote access client id cannot be empty"), "badrequest"))
+		return
+	}
+	if req.RemoteAccessClientID == "" {
+		req.RemoteAccessClientID = remoteAccessClientID
+	}
+	userGws := make(map[string][]models.UserRemoteGws)
+
+	allextClients, err := logic.GetAllExtClients()
+	if err != nil {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+	userGwNodes := logic.GetUserRAGNodes(*user)
+	logger.Log(0, fmt.Sprintf("1. User Gw Nodes: %+v", userGwNodes))
+	for _, extClient := range allextClients {
+		node, ok := userGwNodes[extClient.IngressGatewayID]
+		if !ok {
+			continue
+		}
+		if extClient.RemoteAccessClientID == req.RemoteAccessClientID && extClient.OwnerID == username {
+
+			host, err := logic.GetHost(node.HostID.String())
+			if err != nil {
+				continue
+			}
+			network, err := logic.GetNetwork(node.Network)
+			if err != nil {
+				slog.Error("failed to get node network", "error", err)
+			}
+
+			gws := userGws[node.Network]
+			extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
+			gws = append(gws, models.UserRemoteGws{
+				GwID:              node.ID.String(),
+				GWName:            host.Name,
+				Network:           node.Network,
+				GwClient:          extClient,
+				Connected:         true,
+				IsInternetGateway: node.IsInternetGateway,
+				GwPeerPublicKey:   host.PublicKey.String(),
+				GwListenPort:      logic.GetPeerListenPort(host),
+				Metadata:          node.Metadata,
+				AllowedEndpoints:  getAllowedRagEndpoints(&node, host),
+				NetworkAddresses:  []string{network.AddressRange, network.AddressRange6},
+			})
+			userGws[node.Network] = gws
+			delete(userGwNodes, node.ID.String())
+		}
+	}
+	logger.Log(0, fmt.Sprintf("2. User Gw Nodes: %+v", userGwNodes))
+	// add remaining gw nodes to resp
+	for gwID := range userGwNodes {
+		logger.Log(0, "RAG ---> 1")
+		node, err := logic.GetNodeByID(gwID)
+		if err != nil {
+			continue
+		}
+		if !node.IsIngressGateway {
+			continue
+		}
+		if node.PendingDelete {
+			continue
+		}
+		logger.Log(0, "RAG ---> 2")
+		host, err := logic.GetHost(node.HostID.String())
+		if err != nil {
+			continue
+		}
+		network, err := logic.GetNetwork(node.Network)
+		if err != nil {
+			slog.Error("failed to get node network", "error", err)
+		}
+		logger.Log(0, "RAG ---> 3")
+		gws := userGws[node.Network]
+
+		gws = append(gws, models.UserRemoteGws{
+			GwID:              node.ID.String(),
+			GWName:            host.Name,
+			Network:           node.Network,
+			IsInternetGateway: node.IsInternetGateway,
+			GwPeerPublicKey:   host.PublicKey.String(),
+			GwListenPort:      logic.GetPeerListenPort(host),
+			Metadata:          node.Metadata,
+			AllowedEndpoints:  getAllowedRagEndpoints(&node, host),
+			NetworkAddresses:  []string{network.AddressRange, network.AddressRange6},
+		})
+		userGws[node.Network] = gws
+	}
+
+	if reqFromMobile {
+		// send resp in array format
+		userGwsArr := []models.UserRemoteGws{}
+		for _, userGwI := range userGws {
+			userGwsArr = append(userGwsArr, userGwI...)
+		}
+		logic.ReturnSuccessResponseWithJson(w, r, userGwsArr, "fetched gateways for user"+username)
+		return
+	}
+	slog.Debug("returned user gws", "user", username, "gws", userGws)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(userGws)
+}
+
 // swagger:route GET "/api/users/{username}/remote_access_gw" nodes getUserRemoteAccessGws
 //
 // Get an individual node.