NM-76: add network user api (#3605)

* add network user api

* add remove network user api
This commit is contained in:
Abhishek K
2025-08-25 10:21:52 +05:30
committed by GitHub
parent 8e717fb01b
commit b1f0843d27
5 changed files with 148 additions and 20 deletions

View File

@@ -6,13 +6,14 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/pquerna/otp"
"golang.org/x/crypto/bcrypt"
"image/png"
"net/http"
"reflect"
"time"
"github.com/pquerna/otp"
"golang.org/x/crypto/bcrypt"
"github.com/google/uuid"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
@@ -925,18 +926,16 @@ func getUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
users, err := logic.GetUsers()
for i := range users {
users[i].NumAccessTokens, _ = (&schema.UserAccessToken{
UserName: users[i].UserName,
}).CountByUser(r.Context())
}
if err != nil {
logger.Log(0, "failed to fetch users: ", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
for i := range users {
users[i].NumAccessTokens, _ = (&schema.UserAccessToken{
UserName: users[i].UserName,
}).CountByUser(r.Context())
}
logic.SortUsers(users[:])
logger.Log(2, r.Header.Get("user"), "fetched users")

View File

@@ -62,21 +62,21 @@ var RsrcTypeMap = map[RsrcType]struct{}{
const AllNetworks NetworkID = "all_networks"
const (
HostRsrc RsrcType = "hosts"
RelayRsrc RsrcType = "relays"
HostRsrc RsrcType = "host"
RelayRsrc RsrcType = "relay"
RemoteAccessGwRsrc RsrcType = "remote_access_gw"
GatewayRsrc RsrcType = "gateways"
ExtClientsRsrc RsrcType = "extclients"
GatewayRsrc RsrcType = "gateway"
ExtClientsRsrc RsrcType = "extclient"
InetGwRsrc RsrcType = "inet_gw"
EgressGwRsrc RsrcType = "egress"
NetworkRsrc RsrcType = "networks"
NetworkRsrc RsrcType = "network"
EnrollmentKeysRsrc RsrcType = "enrollment_key"
UserRsrc RsrcType = "users"
UserRsrc RsrcType = "user"
AclRsrc RsrcType = "acl"
TagRsrc RsrcType = "tag"
DnsRsrc RsrcType = "dns"
FailOverRsrc RsrcType = "fail_over"
MetricRsrc RsrcType = "metrics"
MetricRsrc RsrcType = "metric"
)
const (

View File

@@ -5,15 +5,16 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/gravitl/netmaker/pro/idp"
"github.com/gravitl/netmaker/pro/idp/azure"
"github.com/gravitl/netmaker/pro/idp/google"
"github.com/gravitl/netmaker/pro/idp/okta"
"net/http"
"net/url"
"strings"
"time"
"github.com/gravitl/netmaker/pro/idp"
"github.com/gravitl/netmaker/pro/idp/azure"
"github.com/gravitl/netmaker/pro/idp/google"
"github.com/gravitl/netmaker/pro/idp/okta"
"github.com/google/uuid"
"github.com/gorilla/mux"
"github.com/gravitl/netmaker/database"
@@ -48,6 +49,8 @@ func UserHandlers(r *mux.Router) {
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)
r.HandleFunc("/api/v1/users/add_network_user", logic.SecurityCheck(true, http.HandlerFunc(addUsertoNetwork))).Methods(http.MethodPut)
r.HandleFunc("/api/v1/users/remove_network_user", logic.SecurityCheck(true, http.HandlerFunc(removeUserfromNetwork))).Methods(http.MethodPut)
// User Invite Handlers
r.HandleFunc("/api/v1/users/invite", userInviteVerify).Methods(http.MethodGet)
@@ -693,6 +696,120 @@ func updateUserGroup(w http.ResponseWriter, r *http.Request) {
logic.ReturnSuccessResponseWithJson(w, r, userGroup, "updated user group")
}
// swagger:route PUT /api/v1/users/add_network_user user addUsertoNetwork
//
// add user to network.
//
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func addUsertoNetwork(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
if username == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), logic.BadReq))
return
}
netID := r.URL.Query().Get("network_id")
if netID == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network is required"), logic.BadReq))
return
}
user, err := logic.GetUser(username)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
return
}
if user.PlatformRoleID != models.ServiceUser {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("can only add service users"), logic.BadReq))
return
}
oldUser := *user
user.UserGroups[proLogic.GetDefaultNetworkUserGroupID(models.NetworkID(netID))] = struct{}{}
logic.UpsertUser(*user)
logic.LogEvent(&models.Event{
Action: models.Update,
Source: models.Subject{
ID: r.Header.Get("user"),
Name: r.Header.Get("user"),
Type: models.UserSub,
},
TriggeredBy: r.Header.Get("user"),
Target: models.Subject{
ID: user.UserName,
Name: user.UserName,
Type: models.UserSub,
},
Diff: models.Diff{
Old: oldUser,
New: user,
},
Origin: models.Dashboard,
})
logic.ReturnSuccessResponseWithJson(w, r, user, "updated user group")
}
// swagger:route PUT /api/v1/users/remove_network_user user removeUserfromNetwork
//
// add user to network.
//
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: userBodyResponse
func removeUserfromNetwork(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
if username == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), logic.BadReq))
return
}
netID := r.URL.Query().Get("network_id")
if netID == "" {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network is required"), logic.BadReq))
return
}
user, err := logic.GetUser(username)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
return
}
if user.PlatformRoleID != models.ServiceUser {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("can only add service users"), logic.BadReq))
return
}
oldUser := *user
delete(user.UserGroups, proLogic.GetDefaultNetworkUserGroupID(models.NetworkID(netID)))
logic.UpsertUser(*user)
logic.LogEvent(&models.Event{
Action: models.Update,
Source: models.Subject{
ID: r.Header.Get("user"),
Name: r.Header.Get("user"),
Type: models.UserSub,
},
TriggeredBy: r.Header.Get("user"),
Target: models.Subject{
ID: user.UserName,
Name: user.UserName,
Type: models.UserSub,
},
Diff: models.Diff{
Old: oldUser,
New: user,
},
Origin: models.Dashboard,
})
logic.ReturnSuccessResponseWithJson(w, r, user, "updated user group")
}
// swagger:route DELETE /api/v1/user/group user deleteUserGroup
//
// delete user group.

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
@@ -173,6 +174,10 @@ func GlobalPermissionsCheck(username string, r *http.Request) error {
if (targetRsrc == models.HostRsrc.String() || targetRsrc == models.NetworkRsrc.String()) && r.Method == http.MethodGet && targetRsrcID == "" {
return nil
}
if targetRsrc == models.UserRsrc.String() && user.PlatformRoleID == models.PlatformUser && r.Method == http.MethodPut &&
strings.Contains(r.URL.Path, "/api/v1/users/add_network_user") || strings.Contains(r.URL.Path, "/api/v1/users/remove_network_user") {
return nil
}
if targetRsrc == models.UserRsrc.String() && username == targetRsrcID && (r.Method != http.MethodDelete) {
return nil
}

View File

@@ -34,6 +34,13 @@ var PlatformUserUserPermissionTemplate = models.UserRolePermissionTemplate{
ID: models.PlatformUser,
Default: true,
FullAccess: false,
GlobalLevelAccess: map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope{
models.UserRsrc: {
models.AllUserRsrcID: models.RsrcPermissionScope{
Read: true,
},
},
},
}
var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{