|
@@ -0,0 +1,359 @@
|
|
|
+package controller
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "errors"
|
|
|
+ "net/http"
|
|
|
+
|
|
|
+ "github.com/gorilla/mux"
|
|
|
+ "github.com/gravitl/netmaker/logger"
|
|
|
+ "github.com/gravitl/netmaker/logic"
|
|
|
+ "github.com/gravitl/netmaker/logic/pro"
|
|
|
+ "github.com/gravitl/netmaker/models"
|
|
|
+ "github.com/gravitl/netmaker/models/promodels"
|
|
|
+)
|
|
|
+
|
|
|
+func networkUsersHandlers(r *mux.Router) {
|
|
|
+ r.HandleFunc("/api/networkusers", securityCheck(true, http.HandlerFunc(getAllNetworkUsers))).Methods("GET")
|
|
|
+ r.HandleFunc("/api/networkusers/{network}", securityCheck(true, http.HandlerFunc(getNetworkUsers))).Methods("GET")
|
|
|
+ r.HandleFunc("/api/networkusers/{network}/{networkuser}", securityCheck(true, http.HandlerFunc(getNetworkUser))).Methods("GET")
|
|
|
+ r.HandleFunc("/api/networkusers/{network}", securityCheck(true, http.HandlerFunc(createNetworkUser))).Methods("POST")
|
|
|
+ r.HandleFunc("/api/networkusers/{network}", securityCheck(true, http.HandlerFunc(updateNetworkUser))).Methods("PUT")
|
|
|
+ r.HandleFunc("/api/networkusers/data/{networkuser}/me", netUserSecurityCheck(false, false, http.HandlerFunc(getNetworkUserData))).Methods("GET")
|
|
|
+ r.HandleFunc("/api/networkusers/{network}/{networkuser}", securityCheck(true, http.HandlerFunc(deleteNetworkUser))).Methods("DELETE")
|
|
|
+}
|
|
|
+
|
|
|
+// == RETURN TYPES ==
|
|
|
+
|
|
|
+// NetworkName - represents a network name/ID
|
|
|
+type NetworkName string
|
|
|
+
|
|
|
+// NetworkUserDataMap - map of all data per network for a user
|
|
|
+type NetworkUserDataMap map[NetworkName]NetworkUserData
|
|
|
+
|
|
|
+// NetworkUserData - data struct for network users
|
|
|
+type NetworkUserData struct {
|
|
|
+ Nodes []models.Node `json:"nodes" bson:"nodes" yaml:"nodes"`
|
|
|
+ Clients []models.ExtClient `json:"clients" bson:"clients" yaml:"clients"`
|
|
|
+ Vpn []models.Node `json:"vpns" bson:"vpns" yaml:"vpns"`
|
|
|
+ Networks []models.Network `json:"networks" bson:"networks" yaml:"networks"`
|
|
|
+ User promodels.NetworkUser `json:"user" bson:"user" yaml:"user"`
|
|
|
+}
|
|
|
+
|
|
|
+// == END RETURN TYPES ==
|
|
|
+
|
|
|
+// returns a map of a network user's data across all networks
|
|
|
+func getNetworkUserData(w http.ResponseWriter, r *http.Request) {
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
+
|
|
|
+ var params = mux.Vars(r)
|
|
|
+ networkUserName := params["networkuser"]
|
|
|
+ logger.Log(1, r.Header.Get("user"), "requested fetching network user data for user", networkUserName)
|
|
|
+
|
|
|
+ networks, err := logic.GetNetworks()
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if networkUserName == "" {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("netuserToGet"), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ u, err := logic.GetUser(networkUserName)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("could not find user"), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // initialize the return data of network users
|
|
|
+ returnData := make(NetworkUserDataMap)
|
|
|
+
|
|
|
+ // go through each network and get that user's data
|
|
|
+ // if user has no access, give no data
|
|
|
+ // if user is a net admin, give all nodes
|
|
|
+ // if user has node access, give user's nodes if any
|
|
|
+ // if user has client access, git user's clients if any
|
|
|
+ for i := range networks {
|
|
|
+
|
|
|
+ netID := networks[i].NetID
|
|
|
+ newData := NetworkUserData{
|
|
|
+ Nodes: []models.Node{},
|
|
|
+ Clients: []models.ExtClient{},
|
|
|
+ Vpn: []models.Node{},
|
|
|
+ Networks: []models.Network{},
|
|
|
+ }
|
|
|
+ netUser, err := pro.GetNetworkUser(netID, promodels.NetworkUserID(networkUserName))
|
|
|
+ // check if user has access
|
|
|
+ if err == nil && netUser.AccessLevel != pro.NO_ACCESS {
|
|
|
+ newData.User = promodels.NetworkUser{
|
|
|
+ AccessLevel: netUser.AccessLevel,
|
|
|
+ ClientLimit: netUser.ClientLimit,
|
|
|
+ NodeLimit: netUser.NodeLimit,
|
|
|
+ Nodes: netUser.Nodes,
|
|
|
+ Clients: netUser.Clients,
|
|
|
+ }
|
|
|
+ // check network level permissions
|
|
|
+ if doesNetworkAllow := pro.IsUserAllowed(&networks[i], networkUserName, u.Groups); doesNetworkAllow {
|
|
|
+ netNodes, err := logic.GetNetworkNodes(netID)
|
|
|
+ if err != nil {
|
|
|
+ logger.Log(0, "failed to retrieve nodes on network", netID, "for user", string(netUser.ID))
|
|
|
+ } else {
|
|
|
+ if netUser.AccessLevel <= pro.NODE_ACCESS { // handle nodes
|
|
|
+ // if access level is NODE_ACCESS, filter nodes
|
|
|
+ if netUser.AccessLevel == pro.NODE_ACCESS {
|
|
|
+ for i := range netNodes {
|
|
|
+ if logic.StringSliceContains(netUser.Nodes, netNodes[i].ID) {
|
|
|
+ newData.Nodes = append(newData.Nodes, netNodes[i])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else { // net admin so, get all nodes and ext clients on network...
|
|
|
+ newData.Nodes = netNodes
|
|
|
+ for i := range netNodes {
|
|
|
+ if netNodes[i].IsIngressGateway == "yes" {
|
|
|
+ newData.Vpn = append(newData.Vpn, netNodes[i])
|
|
|
+ if clients, err := logic.GetExtClientsByID(netNodes[i].ID, netID); err == nil {
|
|
|
+ newData.Clients = append(newData.Clients, clients...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ newData.Networks = append(newData.Networks, networks[i])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if netUser.AccessLevel <= pro.CLIENT_ACCESS && netUser.AccessLevel != pro.NET_ADMIN {
|
|
|
+ for _, c := range netUser.Clients {
|
|
|
+ if client, err := logic.GetExtClient(c, netID); err == nil {
|
|
|
+ newData.Clients = append(newData.Clients, client)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for i := range netNodes {
|
|
|
+ if netNodes[i].IsIngressGateway == "yes" {
|
|
|
+ newData.Vpn = append(newData.Vpn, netNodes[i])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ returnData[NetworkName(netID)] = newData
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ w.WriteHeader(http.StatusOK)
|
|
|
+ json.NewEncoder(w).Encode(returnData)
|
|
|
+}
|
|
|
+
|
|
|
+// returns a map of all network users mapped to each network
|
|
|
+func getAllNetworkUsers(w http.ResponseWriter, r *http.Request) {
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
+ logger.Log(1, r.Header.Get("user"), "requested fetching all network users")
|
|
|
+ type allNetworkUsers = map[string][]promodels.NetworkUser
|
|
|
+
|
|
|
+ networks, err := logic.GetNetworks()
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var allNetUsers = make(allNetworkUsers, len(networks))
|
|
|
+
|
|
|
+ for i := range networks {
|
|
|
+ netusers, err := pro.GetNetworkUsers(networks[i].NetID)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for _, v := range netusers {
|
|
|
+ allNetUsers[networks[i].NetID] = append(allNetUsers[networks[i].NetID], v)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ w.WriteHeader(http.StatusOK)
|
|
|
+ json.NewEncoder(w).Encode(allNetUsers)
|
|
|
+}
|
|
|
+
|
|
|
+func getNetworkUsers(w http.ResponseWriter, r *http.Request) {
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
+
|
|
|
+ var params = mux.Vars(r)
|
|
|
+ netname := params["network"]
|
|
|
+ logger.Log(1, r.Header.Get("user"), "requested fetching network users for network", netname)
|
|
|
+
|
|
|
+ _, err := logic.GetNetwork(netname)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ netusers, err := pro.GetNetworkUsers(netname)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ w.WriteHeader(http.StatusOK)
|
|
|
+ json.NewEncoder(w).Encode(netusers)
|
|
|
+}
|
|
|
+
|
|
|
+func getNetworkUser(w http.ResponseWriter, r *http.Request) {
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
+
|
|
|
+ var params = mux.Vars(r)
|
|
|
+ netname := params["network"]
|
|
|
+ logger.Log(1, r.Header.Get("user"), "requested fetching network user", params["networkuser"], "on network", netname)
|
|
|
+
|
|
|
+ _, err := logic.GetNetwork(netname)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ netuserToGet := params["networkuser"]
|
|
|
+ if netuserToGet == "" {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("netuserToGet"), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ netuser, err := pro.GetNetworkUser(netname, promodels.NetworkUserID(netuserToGet))
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ w.WriteHeader(http.StatusOK)
|
|
|
+ json.NewEncoder(w).Encode(netuser)
|
|
|
+}
|
|
|
+
|
|
|
+func createNetworkUser(w http.ResponseWriter, r *http.Request) {
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
+ var params = mux.Vars(r)
|
|
|
+ netname := params["network"]
|
|
|
+ logger.Log(1, r.Header.Get("user"), "requested creating a network user on network", netname)
|
|
|
+
|
|
|
+ network, err := logic.GetNetwork(netname)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var networkuser promodels.NetworkUser
|
|
|
+
|
|
|
+ // we decode our body request params
|
|
|
+ err = json.NewDecoder(r.Body).Decode(&networkuser)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ err = pro.CreateNetworkUser(&network, &networkuser)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ w.WriteHeader(http.StatusOK)
|
|
|
+}
|
|
|
+
|
|
|
+func updateNetworkUser(w http.ResponseWriter, r *http.Request) {
|
|
|
+ w.Header().Set("Content-Type", "application/json")
|
|
|
+
|
|
|
+ var params = mux.Vars(r)
|
|
|
+ netname := params["network"]
|
|
|
+ logger.Log(1, r.Header.Get("user"), "requested updating a network user on network", netname)
|
|
|
+
|
|
|
+ network, err := logic.GetNetwork(netname)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var networkuser promodels.NetworkUser
|
|
|
+
|
|
|
+ // we decode our body request params
|
|
|
+ err = json.NewDecoder(r.Body).Decode(&networkuser)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if networkuser.ID == "" || !pro.DoesNetworkUserExist(netname, networkuser.ID) {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("invalid user "+string(networkuser.ID)), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if networkuser.AccessLevel < pro.NET_ADMIN || networkuser.AccessLevel > pro.NO_ACCESS {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("invalid user access level provided"), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if networkuser.ClientLimit < 0 || networkuser.NodeLimit < 0 {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("negative user limit provided"), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ u, err := logic.GetUser(string(networkuser.ID))
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("invalid user "+string(networkuser.ID)), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if !pro.IsUserAllowed(&network, u.UserName, u.Groups) {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("user must be in allowed groups or users"), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if networkuser.AccessLevel == pro.NET_ADMIN {
|
|
|
+ currentUser, err := logic.GetUser(string(networkuser.ID))
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("user model not found for "+string(networkuser.ID)), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if !logic.StringSliceContains(currentUser.Networks, netname) {
|
|
|
+ // append network name to user model to conform to old model
|
|
|
+ if err = logic.UpdateUserNetworks(
|
|
|
+ append(currentUser.Networks, netname),
|
|
|
+ currentUser.Groups,
|
|
|
+ currentUser.IsAdmin,
|
|
|
+ &models.ReturnUser{
|
|
|
+ Groups: currentUser.Groups,
|
|
|
+ IsAdmin: currentUser.IsAdmin,
|
|
|
+ Networks: currentUser.Networks,
|
|
|
+ UserName: currentUser.UserName,
|
|
|
+ },
|
|
|
+ ); err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("user model failed net admin update "+string(networkuser.ID)+" (are they an admin?"), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ err = pro.UpdateNetworkUser(netname, &networkuser)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ w.WriteHeader(http.StatusOK)
|
|
|
+}
|
|
|
+
|
|
|
+func deleteNetworkUser(w http.ResponseWriter, r *http.Request) {
|
|
|
+
|
|
|
+ var params = mux.Vars(r)
|
|
|
+ netname := params["network"]
|
|
|
+
|
|
|
+ logger.Log(1, r.Header.Get("user"), "requested deleting network user", params["networkuser"], "on network", netname)
|
|
|
+
|
|
|
+ _, err := logic.GetNetwork(netname)
|
|
|
+ if err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ netuserToDelete := params["networkuser"]
|
|
|
+ if netuserToDelete == "" {
|
|
|
+ returnErrorResponse(w, r, formatError(errors.New("no group name provided"), "badrequest"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := pro.DeleteNetworkUser(netname, netuserToDelete); err != nil {
|
|
|
+ returnErrorResponse(w, r, formatError(err, "internal"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ w.WriteHeader(http.StatusOK)
|
|
|
+}
|