Browse Source

api to transfer superadmin role

Abhishek Kondur 2 years ago
parent
commit
76ec51e852
3 changed files with 126 additions and 3 deletions
  1. 61 0
      controllers/node.go
  2. 61 3
      controllers/user.go
  3. 4 0
      logic/auth.go

+ 61 - 0
controllers/node.go

@@ -30,6 +30,7 @@ func nodeHandlers(r *mux.Router) {
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", Authorize(false, true, "user", http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", Authorize(false, true, "user", http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/ingress/users", logic.SecurityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
 	r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
 	r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
@@ -595,6 +596,66 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	runUpdates(&node, true)
 	runUpdates(&node, true)
 }
 }
 
 
+// swagger:route GET /api/nodes/{network}/{nodeid}/ingress/users nodes IngressGatewayUsers
+//
+// Lists all the users attached to an ingress gateway.
+//
+//			Schemes: https
+//
+//			Security:
+//	  		oauth
+//
+//			Responses:
+//				200: nodeResponse
+func IngressGatewayUsers(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	nodeid := params["nodeid"]
+	netid := params["network"]
+	node, err := validateParams(nodeid, netid)
+	if err != nil {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "bad request"))
+		return
+	}
+	node, wasFailover, removedClients, err := logic.DeleteIngressGateway(nodeid)
+	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to delete ingress gateway on node [%s] on network [%s]: %v",
+				nodeid, netid, err))
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+
+	if servercfg.Is_EE && wasFailover {
+		if err = logic.EnterpriseResetFailoverFunc(node.Network); err != nil {
+			logger.Log(1, "failed to reset failover list during failover create", node.ID.String(), node.Network)
+		}
+	}
+
+	apiNode := node.ConvertToAPINode()
+	logger.Log(1, r.Header.Get("user"), "deleted ingress gateway", nodeid)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(apiNode)
+
+	if len(removedClients) > 0 {
+		host, err := logic.GetHost(node.HostID.String())
+		if err == nil {
+			allNodes, err := logic.GetAllNodes()
+			if err != nil {
+				return
+			}
+			go mq.PublishSingleHostPeerUpdate(
+				host,
+				allNodes,
+				nil,
+				removedClients[:],
+			)
+		}
+	}
+
+	runUpdates(&node, true)
+}
+
 // swagger:route PUT /api/nodes/{network}/{nodeid} nodes updateNode
 // swagger:route PUT /api/nodes/{network}/{nodeid} nodes updateNode
 //
 //
 // Update an individual node.
 // Update an individual node.

+ 61 - 3
controllers/user.go

@@ -26,6 +26,7 @@ var verifyJWT = logic.VerifyJWT
 func userHandlers(r *mux.Router) {
 func userHandlers(r *mux.Router) {
 	r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet)
 	r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet)
 	r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost)
 	r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost)
+	r.HandleFunc("/api/users/adm/transfersuperadmin", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).Methods(http.MethodPost)
 	r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)
 	r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)
 	r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(true, http.HandlerFunc(attachUserToRemoteAccessGw))).Methods(http.MethodPost)
 	r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(true, http.HandlerFunc(attachUserToRemoteAccessGw))).Methods(http.MethodPost)
 	r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(true, http.HandlerFunc(removeUserFromRemoteAccessGW))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(true, http.HandlerFunc(removeUserFromRemoteAccessGW))).Methods(http.MethodDelete)
@@ -460,6 +461,63 @@ func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(logic.ToReturnUser(u))
 	json.NewEncoder(w).Encode(logic.ToReturnUser(u))
 }
 }
 
 
+// swagger:route POST /api/users/adm/transfersuperadmin user transferSuperAdmin
+//
+// Transfers suoeradmin role to an admin user.
+//
+//			Schemes: https
+//
+//			Security:
+//	  		oauth
+//
+//			Responses:
+//				200: userBodyResponse
+func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	caller, err := logic.GetUser(r.Header.Get("user"))
+	if err != nil {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+	}
+	if !caller.IsSuperAdmin {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can assign the superadmin role to another user"), "forbidden"))
+		return
+	}
+	var u models.User
+	err = json.NewDecoder(r.Body).Decode(&u)
+	if err != nil {
+		slog.Error("error decoding request body: ", "error", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	if !u.IsAdmin {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden"))
+		return
+	}
+	if !servercfg.IsBasicAuthEnabled() {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"))
+		return
+	}
+
+	u.IsSuperAdmin = true
+	u.IsAdmin = false
+	err = logic.UpsertUser(u)
+	if err != nil {
+		slog.Error("error updating user to superadmin: ", "user", u.UserName, "error", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+	caller.IsSuperAdmin = false
+	caller.IsAdmin = true
+	err = logic.UpsertUser(*caller)
+	if err != nil {
+		slog.Error("error demoting user to admin: ", "user", caller.UserName, "error", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+	slog.Info("user was made a super admin", "user", u.UserName)
+	json.NewEncoder(w).Encode(logic.ToReturnUser(u))
+}
+
 // swagger:route POST /api/users/{username} user createUser
 // swagger:route POST /api/users/{username} user createUser
 //
 //
 // Create a user.
 // Create a user.
@@ -488,13 +546,13 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 	if !caller.IsSuperAdmin && user.IsAdmin {
 	if !caller.IsSuperAdmin && user.IsAdmin {
 		slog.Error("error creating new user: ", "user", user.UserName, "error",
 		slog.Error("error creating new user: ", "user", user.UserName, "error",
 			errors.New("only superadmin can create admin users"))
 			errors.New("only superadmin can create admin users"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
 		return
 		return
 	}
 	}
 	if user.IsSuperAdmin {
 	if user.IsSuperAdmin {
 		slog.Error("error creating new user: ", "user", user.UserName, "error",
 		slog.Error("error creating new user: ", "user", user.UserName, "error",
 			errors.New("additional superadmins cannot be created"))
 			errors.New("additional superadmins cannot be created"))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
 		return
 		return
 	}
 	}
 
 
@@ -570,7 +628,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 				return
 				return
 			}
 			}
 		}
 		}
-		if caller.IsAdmin && user.IsAdmin {
+		if caller.IsAdmin && userchange.IsAdmin {
 			slog.Error("admin user cannot update another admin", "caller", caller.UserName, "attempted to update admin user", username)
 			slog.Error("admin user cannot update another admin", "caller", caller.UserName, "attempted to update admin user", username)
 			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("admin user cannot update another admin"), "forbidden"))
 			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("admin user cannot update another admin"), "forbidden"))
 			return
 			return

+ 4 - 0
logic/auth.go

@@ -166,6 +166,10 @@ func UpdateUser(userchange, user *models.User) (*models.User, error) {
 	queryUser := user.UserName
 	queryUser := user.UserName
 
 
 	if userchange.UserName != "" {
 	if userchange.UserName != "" {
+		// check if username is available
+		if _, err := GetUser(userchange.UserName); err == nil {
+			return &models.User{}, errors.New("username exists already")
+		}
 		user.UserName = userchange.UserName
 		user.UserName = userchange.UserName
 	}
 	}