diff --git a/controllers/ext_client.go b/controllers/ext_client.go index f0b36ae41..2678fbf50 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -355,30 +355,28 @@ func createExtClient(w http.ResponseWriter, r *http.Request) { return } userName = caller.UserName - if !caller.IsAdmin && !caller.IsSuperAdmin { - if _, ok := caller.RemoteGwIDs[nodeid]; !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 { - slog.Error("failed to get extclients", "error", err) - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + if _, ok := caller.RemoteGwIDs[nodeid]; (!caller.IsAdmin && !caller.IsSuperAdmin) && !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 { + slog.Error("failed to get extclients", "error", err) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + for _, extclient := range extclients { + if extclient.RemoteAccessClientID != "" && + extclient.RemoteAccessClientID == customExtClient.RemoteAccessClientID && nodeid == extclient.IngressGatewayID { + // extclient on the gw already exists for the remote access client + err = errors.New("remote client config already exists on the gateway. it may have been created by another user with this same remote client machine") + slog.Error("failed to create extclient", "user", userName, "error", err) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - for _, extclient := range extclients { - if extclient.RemoteAccessClientID != "" && - extclient.RemoteAccessClientID == customExtClient.RemoteAccessClientID && nodeid == extclient.IngressGatewayID { - // extclient on the gw already exists for the remote access client - err = errors.New("remote client config already exists on the gateway") - slog.Error("failed to create extclient", "user", userName, "error", err) - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) - return - } - } } } diff --git a/models/extclient.go b/models/extclient.go index 229b3f807..7fb3c0be4 100644 --- a/models/extclient.go +++ b/models/extclient.go @@ -16,7 +16,7 @@ type ExtClient struct { Enabled bool `json:"enabled" bson:"enabled"` OwnerID string `json:"ownerid" bson:"ownerid"` DeniedACLs map[string]struct{} `json:"deniednodeacls" bson:"acls,omitempty"` - RemoteAccessClientID string `json:"remote_access_client_id"` + RemoteAccessClientID string `json:"remote_access_client_id"` // unique ID (MAC address) of RAC machine } // CustomExtClient - struct for CustomExtClient params @@ -27,5 +27,5 @@ type CustomExtClient struct { ExtraAllowedIPs []string `json:"extraallowedips,omitempty"` Enabled bool `json:"enabled,omitempty"` DeniedACLs map[string]struct{} `json:"deniednodeacls" bson:"acls,omitempty"` - RemoteAccessClientID string `json:"remote_access_client_id"` + RemoteAccessClientID string `json:"remote_access_client_id"` // unique ID (MAC address) of RAC machine } diff --git a/pro/controllers/users.go b/pro/controllers/users.go index 6c525cbf3..d0e46d3b3 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -166,16 +166,13 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest")) return } - if user.IsAdmin || user.IsSuperAdmin { - logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("admins can visit dashboard to create remote clients"), "badrequest")) - return - } allextClients, err := logic.GetAllExtClients() if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } + processedAdminNodeIds := make(map[string]struct{}) for _, extClient := range allextClients { if extClient.RemoteAccessClientID == req.RemoteAccessClientID && extClient.OwnerID == username { node, err := logic.GetNodeByID(extClient.IngressGatewayID) @@ -193,7 +190,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) { continue } - if _, ok := user.RemoteGwIDs[node.ID.String()]; ok { + if _, ok := user.RemoteGwIDs[node.ID.String()]; (!user.IsAdmin && !user.IsSuperAdmin) && ok { gws := userGws[node.Network] gws = append(gws, models.UserRemoteGws{ @@ -206,39 +203,77 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) { }) userGws[node.Network] = gws delete(user.RemoteGwIDs, node.ID.String()) - + } else { + gws := userGws[node.Network] + gws = append(gws, models.UserRemoteGws{ + GwID: node.ID.String(), + GWName: host.Name, + Network: node.Network, + GwClient: extClient, + Connected: true, + IsInternetGateway: node.IsInternetGateway, + }) + userGws[node.Network] = gws + processedAdminNodeIds[node.ID.String()] = struct{}{} } } - } // add remaining gw nodes to resp - for gwID := range user.RemoteGwIDs { - node, err := logic.GetNodeByID(gwID) - if err != nil { - continue - } - if !node.IsIngressGateway { - continue - } - if node.PendingDelete { - continue + if !user.IsAdmin && !user.IsSuperAdmin { + for gwID := range user.RemoteGwIDs { + node, err := logic.GetNodeByID(gwID) + if err != nil { + continue + } + if !node.IsIngressGateway { + continue + } + if node.PendingDelete { + continue + } + host, err := logic.GetHost(node.HostID.String()) + if err != nil { + continue + } + gws := userGws[node.Network] + + gws = append(gws, models.UserRemoteGws{ + GwID: node.ID.String(), + GWName: host.Name, + Network: node.Network, + IsInternetGateway: node.IsInternetGateway, + }) + userGws[node.Network] = gws } - host, err := logic.GetHost(node.HostID.String()) + } else { + allNodes, err := logic.GetAllNodes() if err != nil { - continue + slog.Error("failed to fetch all nodes", "error", err) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return } - gws := userGws[node.Network] + for _, node := range allNodes { + _, ok := processedAdminNodeIds[node.ID.String()] + if node.IsIngressGateway && !node.PendingDelete && !ok { + host, err := logic.GetHost(node.HostID.String()) + if err != nil { + slog.Error("failed to fetch host", "error", err) + continue + } + gws := userGws[node.Network] - gws = append(gws, models.UserRemoteGws{ - GwID: node.ID.String(), - GWName: host.Name, - Network: node.Network, - IsInternetGateway: node.IsInternetGateway, - }) - userGws[node.Network] = gws + gws = append(gws, models.UserRemoteGws{ + GwID: node.ID.String(), + GWName: host.Name, + Network: node.Network, + IsInternetGateway: node.IsInternetGateway, + }) + userGws[node.Network] = gws + } + } } - + slog.Debug("returned user gws", "user", username, "gws", userGws) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(userGws) }