mirror of
https://github.com/gravitl/netmaker.git
synced 2024-09-20 07:16:06 +08:00
NET-551: User Mgmt Re-Design (#2547)
* add superadmin role, apis to create superadmin user * apis to attach and remove user from remote access gateways * add api to list user's remote client has gateway clients * remove code related user groups * remove networks and groups from user model * refactor user CRUD operations * fix network permission test * add superadmin to authorize func * remove user network and groups from cli * api to transfer superadmin role * add api to list users on a ingress gw * restrict user access to resources on server * deny request from remote access client if extclient is already created * fix user tests * fix static checks * fix static checks * add limits to extclient create handler * set username to superadmin on if masterkey is used * allow creation of extclients using masterkey * add migration func to assign superadmin role for existing admin user * check for superadmin on migration if users are present * allowe masterkey to extcleint apis * check ownerid * format error, on jwt token verification failure return unauthorized rather than forbidden * user update fix * move user remote functionality to ee * fix update user api * security patch * initalise ee user handlers * allow user to use master key to update any user * use slog * fix auth user test * table headers * remove user role, it's covered in middleware * setuser defaults fix
This commit is contained in:
parent
1a1ba1ccf4
commit
719e0c254d
13
auth/auth.go
13
auth/auth.go
|
@ -10,6 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/exp/slog"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
|
@ -238,9 +239,9 @@ func HandleHeadlessSSO(w http.ResponseWriter, r *http.Request) {
|
|||
// == private methods ==
|
||||
|
||||
func addUser(email string) error {
|
||||
var hasAdmin, err = logic.HasAdmin()
|
||||
var hasSuperAdmin, err = logic.HasSuperAdmin()
|
||||
if err != nil {
|
||||
logger.Log(1, "error checking for existence of admin user during OAuth login for", email, "; user not added")
|
||||
slog.Error("error checking for existence of admin user during OAuth login for", "email", email, "error", err)
|
||||
return err
|
||||
} // generate random password to adapt to current model
|
||||
var newPass, fetchErr = fetchPassValue("")
|
||||
|
@ -251,11 +252,11 @@ func addUser(email string) error {
|
|||
UserName: email,
|
||||
Password: newPass,
|
||||
}
|
||||
if !hasAdmin { // must be first attempt, create an admin
|
||||
if err = logic.CreateAdmin(&newUser); err != nil {
|
||||
logger.Log(1, "error creating admin from user,", email, "; user not added")
|
||||
if !hasSuperAdmin { // must be first attempt, create a superadmin
|
||||
if err = logic.CreateSuperAdmin(&newUser); err != nil {
|
||||
slog.Error("error creating super admin from user", "email", email, "error", err)
|
||||
} else {
|
||||
logger.Log(1, "admin created from user,", email, "; was first user added")
|
||||
slog.Info("superadmin created from user", "email", email)
|
||||
}
|
||||
} else { // otherwise add to db as admin..?
|
||||
// TODO: add ability to add users with preemptive permissions
|
||||
|
|
|
@ -9,10 +9,8 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"github.com/gravitl/netmaker/logic/pro/netcache"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -165,25 +163,5 @@ func isUserIsAllowed(username, network string, shouldAddUser bool) (*models.User
|
|||
user, _ = logic.GetUser(username)
|
||||
}
|
||||
|
||||
if !user.IsAdmin { // perform check to see if user is allowed to join a node to network
|
||||
netUser, err := pro.GetNetworkUser(network, promodels.NetworkUserID(user.UserName))
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to get net user details for user", user.UserName, "during node SSO")
|
||||
return nil, fmt.Errorf("failed to verify network user")
|
||||
}
|
||||
if netUser.AccessLevel != pro.NET_ADMIN { // if user is a net admin on network, good to go
|
||||
// otherwise, check if they have node access + haven't reached node limit on network
|
||||
if netUser.AccessLevel == pro.NODE_ACCESS {
|
||||
if len(netUser.Nodes) >= netUser.NodeLimit {
|
||||
logger.Log(0, "user", user.UserName, "has reached their node limit on network", network)
|
||||
return nil, fmt.Errorf("user node limit exceeded")
|
||||
}
|
||||
} else {
|
||||
logger.Log(0, "user", user.UserName, "attempted to access network", network, "via node SSO")
|
||||
return nil, fmt.Errorf("network user not allowed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
package network_user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var networkuserCreateCmd = &cobra.Command{
|
||||
Use: "create [NETWORK NAME]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Create a network user",
|
||||
Long: `Create a network user`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
user := &promodels.NetworkUser{
|
||||
AccessLevel: accessLevel,
|
||||
ClientLimit: clientLimit,
|
||||
NodeLimit: nodeLimit, ID: promodels.NetworkUserID(id),
|
||||
}
|
||||
if clients != "" {
|
||||
user.Clients = strings.Split(clients, ",")
|
||||
}
|
||||
if nodes != "" {
|
||||
user.Nodes = strings.Split(nodes, ",")
|
||||
}
|
||||
functions.CreateNetworkUser(args[0], user)
|
||||
fmt.Println("Success")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
networkuserCreateCmd.Flags().IntVar(&accessLevel, "access_level", 0, "Custom access level")
|
||||
networkuserCreateCmd.Flags().IntVar(&clientLimit, "client_limit", 0, "Maximum number of external clients that can be created")
|
||||
networkuserCreateCmd.Flags().IntVar(&nodeLimit, "node_limit", 999999999, "Maximum number of nodes that can be attached to a network")
|
||||
networkuserCreateCmd.Flags().StringVar(&clients, "clients", "", "Access to list of external clients (comma separated)")
|
||||
networkuserCreateCmd.Flags().StringVar(&nodes, "nodes", "", "Access to list of nodes (comma separated)")
|
||||
networkuserCreateCmd.Flags().StringVar(&id, "id", "", "ID of the network user")
|
||||
networkuserCreateCmd.MarkFlagRequired("id")
|
||||
rootCmd.AddCommand(networkuserCreateCmd)
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package network_user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var networkuserDeleteCmd = &cobra.Command{
|
||||
Use: "delete [NETWORK NAME] [NETWORK USER NAME]",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Short: "Delete a network user",
|
||||
Long: `Delete a network user`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
functions.DeleteNetworkUser(args[0], args[1])
|
||||
fmt.Println("Success")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(networkuserDeleteCmd)
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package network_user
|
||||
|
||||
var (
|
||||
accessLevel int
|
||||
clientLimit int
|
||||
nodeLimit int
|
||||
clients string
|
||||
nodes string
|
||||
id string
|
||||
)
|
|
@ -1,27 +0,0 @@
|
|||
package network_user
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var data bool
|
||||
|
||||
var networkuserGetCmd = &cobra.Command{
|
||||
Use: "get [NETWORK NAME] [NETWORK USER NAME]",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Short: "Fetch a network user",
|
||||
Long: `Fetch a network user`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if data {
|
||||
functions.PrettyPrint(functions.GetNetworkUserData(args[1]))
|
||||
} else {
|
||||
functions.PrettyPrint(functions.GetNetworkUser(args[0], args[1]))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
networkuserGetCmd.Flags().BoolVar(&data, "data", false, "Fetch entire data of a network user")
|
||||
rootCmd.AddCommand(networkuserGetCmd)
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package network_user
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var networkName string
|
||||
|
||||
var networkuserListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Args: cobra.NoArgs,
|
||||
Short: "List network users",
|
||||
Long: `List network users`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if networkName != "" {
|
||||
functions.PrettyPrint(functions.GetNetworkUsers(networkName))
|
||||
} else {
|
||||
functions.PrettyPrint(functions.GetAllNetworkUsers())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
networkuserListCmd.Flags().StringVar(&networkName, "network", "", "Name of the network")
|
||||
rootCmd.AddCommand(networkuserListCmd)
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package network_user
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "network_user",
|
||||
Short: "Manage Network Users",
|
||||
Long: `Manage Network Users`,
|
||||
}
|
||||
|
||||
// GetRoot returns the root subcommand
|
||||
func GetRoot() *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package network_user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var networkuserUpdateCmd = &cobra.Command{
|
||||
Use: "update [NETWORK NAME]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Update a network user",
|
||||
Long: `Update a network user`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
user := &promodels.NetworkUser{
|
||||
AccessLevel: accessLevel,
|
||||
ClientLimit: clientLimit,
|
||||
NodeLimit: nodeLimit, ID: promodels.NetworkUserID(id),
|
||||
}
|
||||
if clients != "" {
|
||||
user.Clients = strings.Split(clients, ",")
|
||||
}
|
||||
if nodes != "" {
|
||||
user.Nodes = strings.Split(nodes, ",")
|
||||
}
|
||||
functions.UpdateNetworkUser(args[0], user)
|
||||
fmt.Println("Success")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
networkuserUpdateCmd.Flags().IntVar(&accessLevel, "access_level", 0, "Custom access level")
|
||||
networkuserUpdateCmd.Flags().IntVar(&clientLimit, "client_limit", 0, "Maximum number of external clients that can be created")
|
||||
networkuserUpdateCmd.Flags().IntVar(&nodeLimit, "node_limit", 999999999, "Maximum number of nodes that can be attached to a network")
|
||||
networkuserUpdateCmd.Flags().StringVar(&clients, "clients", "", "Access to list of external clients (comma separated)")
|
||||
networkuserUpdateCmd.Flags().StringVar(&nodes, "nodes", "", "Access to list of nodes (comma separated)")
|
||||
networkuserUpdateCmd.Flags().StringVar(&id, "id", "", "ID of the network user")
|
||||
networkuserUpdateCmd.MarkFlagRequired("id")
|
||||
rootCmd.AddCommand(networkuserUpdateCmd)
|
||||
}
|
|
@ -12,11 +12,9 @@ import (
|
|||
"github.com/gravitl/netmaker/cli/cmd/host"
|
||||
"github.com/gravitl/netmaker/cli/cmd/metrics"
|
||||
"github.com/gravitl/netmaker/cli/cmd/network"
|
||||
"github.com/gravitl/netmaker/cli/cmd/network_user"
|
||||
"github.com/gravitl/netmaker/cli/cmd/node"
|
||||
"github.com/gravitl/netmaker/cli/cmd/server"
|
||||
"github.com/gravitl/netmaker/cli/cmd/user"
|
||||
"github.com/gravitl/netmaker/cli/cmd/usergroup"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -52,9 +50,7 @@ func init() {
|
|||
rootCmd.AddCommand(server.GetRoot())
|
||||
rootCmd.AddCommand(ext_client.GetRoot())
|
||||
rootCmd.AddCommand(user.GetRoot())
|
||||
rootCmd.AddCommand(usergroup.GetRoot())
|
||||
rootCmd.AddCommand(metrics.GetRoot())
|
||||
rootCmd.AddCommand(network_user.GetRoot())
|
||||
rootCmd.AddCommand(host.GetRoot())
|
||||
rootCmd.AddCommand(enrollment_key.GetRoot())
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -15,12 +13,6 @@ var userCreateCmd = &cobra.Command{
|
|||
Long: `Create a new user`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
user := &models.User{UserName: username, Password: password, IsAdmin: admin}
|
||||
if networks != "" {
|
||||
user.Networks = strings.Split(networks, ",")
|
||||
}
|
||||
if groups != "" {
|
||||
user.Groups = strings.Split(groups, ",")
|
||||
}
|
||||
functions.PrettyPrint(functions.CreateUser(user))
|
||||
},
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package user
|
|||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/cmd/commons"
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
|
@ -23,9 +22,9 @@ var userListCmd = &cobra.Command{
|
|||
functions.PrettyPrint(data)
|
||||
default:
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Name", "Admin", "Networks", "Groups"})
|
||||
table.SetHeader([]string{"Name", "SuperAdmin", "Admin"})
|
||||
for _, d := range *data {
|
||||
table.Append([]string{d.UserName, strconv.FormatBool(d.IsAdmin), strings.Join(d.Networks, ", "), strings.Join(d.Groups, ", ")})
|
||||
table.Append([]string{d.UserName, strconv.FormatBool(d.IsSuperAdmin), strconv.FormatBool(d.IsAdmin)})
|
||||
}
|
||||
table.Render()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -15,14 +13,6 @@ var userUpdateCmd = &cobra.Command{
|
|||
Long: `Update a user`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
user := &models.User{UserName: args[0], IsAdmin: admin}
|
||||
if networks != "" {
|
||||
user.Networks = strings.Split(networks, ",")
|
||||
}
|
||||
if groups != "" {
|
||||
user.Groups = strings.Split(groups, ",")
|
||||
} else {
|
||||
user.Groups = []string{"*"}
|
||||
}
|
||||
functions.PrettyPrint(functions.UpdateUser(user))
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package usergroup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var usergroupCreateCmd = &cobra.Command{
|
||||
Use: "create [GROUP NAME]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Create a usergroup",
|
||||
Long: `Create a usergroup`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
functions.CreateUsergroup(args[0])
|
||||
fmt.Println("Success")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(usergroupCreateCmd)
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package usergroup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var usergroupDeleteCmd = &cobra.Command{
|
||||
Use: "delete [GROUP NAME]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Delete a usergroup",
|
||||
Long: `Delete a usergroup`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
functions.DeleteUsergroup(args[0])
|
||||
fmt.Println("Success")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(usergroupDeleteCmd)
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package usergroup
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/cli/functions"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var usergroupGetCmd = &cobra.Command{
|
||||
Use: "get",
|
||||
Args: cobra.NoArgs,
|
||||
Short: "Fetch all usergroups",
|
||||
Long: `Fetch all usergroups`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
functions.PrettyPrint(functions.GetUsergroups())
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(usergroupGetCmd)
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package usergroup
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "usergroup",
|
||||
Short: "Manage User Groups",
|
||||
Long: `Manage User Groups`,
|
||||
}
|
||||
|
||||
// GetRoot returns the root subcommand
|
||||
func GetRoot() *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package functions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
proControllers "github.com/gravitl/netmaker/pro/controllers"
|
||||
)
|
||||
|
||||
// GetAllNetworkUsers - fetch all network users
|
||||
func GetAllNetworkUsers() *map[string][]promodels.NetworkUser {
|
||||
return request[map[string][]promodels.NetworkUser](http.MethodGet, "/api/networkusers", nil)
|
||||
}
|
||||
|
||||
// GetNetworkUsers - fetch network users belonging to a particular network
|
||||
func GetNetworkUsers(networkName string) *promodels.NetworkUserMap {
|
||||
return request[promodels.NetworkUserMap](http.MethodGet, "/api/networkusers/"+networkName, nil)
|
||||
}
|
||||
|
||||
// GetNetworkUser - fetch a single network user
|
||||
func GetNetworkUser(networkName, networkUserName string) *promodels.NetworkUser {
|
||||
return request[promodels.NetworkUser](http.MethodGet, fmt.Sprintf("/api/networkusers/%s/%s", networkName, networkUserName), nil)
|
||||
}
|
||||
|
||||
// CreateNetworkUser - create a network user
|
||||
func CreateNetworkUser(networkName string, payload *promodels.NetworkUser) {
|
||||
request[any](http.MethodPost, "/api/networkusers/"+networkName, payload)
|
||||
}
|
||||
|
||||
// UpdateNetworkUser - update a network user
|
||||
func UpdateNetworkUser(networkName string, payload *promodels.NetworkUser) {
|
||||
request[any](http.MethodPut, "/api/networkusers/"+networkName, payload)
|
||||
}
|
||||
|
||||
// GetNetworkUserData - fetch a network user's complete data
|
||||
func GetNetworkUserData(networkUserName string) *proControllers.NetworkUserDataMap {
|
||||
return request[proControllers.NetworkUserDataMap](http.MethodGet, fmt.Sprintf("/api/networkusers/data/%s/me", networkUserName), nil)
|
||||
}
|
||||
|
||||
// DeleteNetworkUser - delete a network user
|
||||
func DeleteNetworkUser(networkName, networkUserName string) {
|
||||
request[any](http.MethodDelete, fmt.Sprintf("/api/networkusers/%s/%s", networkName, networkUserName), nil)
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package functions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
)
|
||||
|
||||
// GetUsergroups - fetch all usergroups
|
||||
func GetUsergroups() *promodels.UserGroups {
|
||||
return request[promodels.UserGroups](http.MethodGet, "/api/usergroups", nil)
|
||||
}
|
||||
|
||||
// CreateUsergroup - create a usergroup
|
||||
func CreateUsergroup(usergroupName string) {
|
||||
request[any](http.MethodPost, "/api/usergroups/"+usergroupName, nil)
|
||||
}
|
||||
|
||||
// DeleteUsergroup - delete a usergroup
|
||||
func DeleteUsergroup(usergroupName string) {
|
||||
request[any](http.MethodDelete, "/api/usergroups/"+usergroupName, nil)
|
||||
}
|
|
@ -17,12 +17,12 @@ import (
|
|||
func dnsHandlers(r *mux.Router) {
|
||||
|
||||
r.HandleFunc("/api/dns", logic.SecurityCheck(true, http.HandlerFunc(getAllDNS))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/dns/adm/{network}/nodes", logic.SecurityCheck(false, http.HandlerFunc(getNodeDNS))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/dns/adm/{network}/custom", logic.SecurityCheck(false, http.HandlerFunc(getCustomDNS))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/dns/adm/{network}", logic.SecurityCheck(false, http.HandlerFunc(getDNS))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/dns/{network}", logic.SecurityCheck(false, http.HandlerFunc(createDNS))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/dns/adm/pushdns", logic.SecurityCheck(false, http.HandlerFunc(pushDNS))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/dns/{network}/{domain}", logic.SecurityCheck(false, http.HandlerFunc(deleteDNS))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/dns/adm/{network}/nodes", logic.SecurityCheck(true, http.HandlerFunc(getNodeDNS))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/dns/adm/{network}/custom", logic.SecurityCheck(true, http.HandlerFunc(getCustomDNS))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/dns/adm/{network}", logic.SecurityCheck(true, http.HandlerFunc(getDNS))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/dns/{network}", logic.SecurityCheck(true, http.HandlerFunc(createDNS))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/dns/adm/pushdns", logic.SecurityCheck(true, http.HandlerFunc(pushDNS))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/dns/{network}/{domain}", logic.SecurityCheck(true, http.HandlerFunc(deleteDNS))).Methods(http.MethodDelete)
|
||||
}
|
||||
|
||||
// swagger:route GET /api/dns/adm/{network}/nodes dns getNodeDNS
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
|
||||
func enrollmentKeyHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/v1/enrollment-keys", logic.SecurityCheck(true, http.HandlerFunc(createEnrollmentKey))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/enrollment-keys", logic.SecurityCheck(false, http.HandlerFunc(getEnrollmentKeys))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/enrollment-keys", logic.SecurityCheck(true, http.HandlerFunc(getEnrollmentKeys))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/enrollment-keys/{keyID}", logic.SecurityCheck(true, http.HandlerFunc(deleteEnrollmentKey))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/v1/host/register/{token}", http.HandlerFunc(handleHostRegister)).Methods(http.MethodPost)
|
||||
}
|
||||
|
@ -40,20 +40,10 @@ func getEnrollmentKeys(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
isMasterAdmin := r.Header.Get("ismaster") == "yes"
|
||||
// regular user flow
|
||||
user, err := logic.GetUser(r.Header.Get("user"))
|
||||
if err != nil && !isMasterAdmin {
|
||||
logger.Log(0, r.Header.Get("user"), "failed to fetch user: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
// TODO drop double pointer
|
||||
|
||||
ret := []*models.EnrollmentKey{}
|
||||
for _, key := range keys {
|
||||
if !isMasterAdmin && !logic.UserHasNetworksAccess(key.Networks, user) {
|
||||
continue
|
||||
}
|
||||
key := key
|
||||
if err = logic.Tokenize(key, servercfg.GetAPIHost()); err != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "failed to get token values for keys:", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
|
|
|
@ -12,9 +12,9 @@ import (
|
|||
"github.com/gravitl/netmaker/database"
|
||||
"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"
|
||||
|
||||
"github.com/gravitl/netmaker/mq"
|
||||
"github.com/skip2/go-qrcode"
|
||||
"golang.org/x/exp/slog"
|
||||
|
@ -23,13 +23,13 @@ import (
|
|||
|
||||
func extClientHandlers(r *mux.Router) {
|
||||
|
||||
r.HandleFunc("/api/extclients", logic.SecurityCheck(false, http.HandlerFunc(getAllExtClients))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/extclients/{network}", logic.SecurityCheck(false, http.HandlerFunc(getNetworkExtClients))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/extclients", logic.SecurityCheck(true, http.HandlerFunc(getAllExtClients))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/extclients/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkExtClients))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(getExtClient))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(getExtClientConf))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(updateExtClient))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(deleteExtClient))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.NetUserSecurityCheck(false, true, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.SecurityCheck(false, http.HandlerFunc(getExtClientConf))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(updateExtClient))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(deleteExtClient))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost)
|
||||
}
|
||||
|
||||
func checkIngressExists(nodeID string) bool {
|
||||
|
@ -94,29 +94,18 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
|
|||
networksSlice := []string{}
|
||||
marshalErr := json.Unmarshal([]byte(headerNetworks), &networksSlice)
|
||||
if marshalErr != nil {
|
||||
logger.Log(0, "error unmarshalling networks: ",
|
||||
marshalErr.Error())
|
||||
slog.Error("error unmarshalling networks", "error", marshalErr.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(marshalErr, "internal"))
|
||||
return
|
||||
}
|
||||
clients := []models.ExtClient{}
|
||||
var err error
|
||||
if len(networksSlice) > 0 && networksSlice[0] == logic.ALL_NETWORK_ACCESS {
|
||||
clients, err = logic.GetAllExtClients()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
logger.Log(0, "failed to get all extclients: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
for _, network := range networksSlice {
|
||||
extclients, err := logic.GetNetworkExtClients(network)
|
||||
if err == nil {
|
||||
clients = append(clients, extclients...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
clients, err := logic.GetAllExtClients()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
logger.Log(0, "failed to get all extclients: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
//Return all the extclients in JSON format
|
||||
logic.SortExtClient(clients[:])
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
@ -149,6 +138,14 @@ 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)
|
||||
|
@ -179,6 +176,12 @@ 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 {
|
||||
|
@ -323,7 +326,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
var customExtClient models.CustomExtClient
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&customExtClient); err != nil {
|
||||
|
@ -334,9 +336,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
extclient := logic.UpdateExtClient(&models.ExtClient{}, &customExtClient)
|
||||
|
||||
extclient.IngressGatewayID = nodeid
|
||||
node, err := logic.GetNodeByID(nodeid)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
|
@ -344,6 +343,48 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
var userName string
|
||||
if r.Header.Get("ismaster") == "yes" {
|
||||
userName = logic.MasterUser
|
||||
} else {
|
||||
caller, err := logic.GetUser(r.Header.Get("user"))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
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"))
|
||||
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 get extclients", "error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extclient := logic.UpdateExtClient(&models.ExtClient{}, &customExtClient)
|
||||
extclient.OwnerID = userName
|
||||
extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID
|
||||
extclient.IngressGatewayID = nodeid
|
||||
|
||||
extclient.Network = node.Network
|
||||
host, err := logic.GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
|
@ -372,26 +413,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var isAdmin bool
|
||||
if r.Header.Get("ismaster") != "yes" {
|
||||
userID := r.Header.Get("user")
|
||||
if isAdmin, err = checkProClientAccess(userID, extclient.ClientID, &parentNetwork); err != nil {
|
||||
slog.Error("pro client access check failed", "user", userID, "network", node.Network, "error", err)
|
||||
logic.DeleteExtClient(node.Network, extclient.ClientID)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if !isAdmin {
|
||||
if err = pro.AssociateNetworkUserClient(userID, node.Network, extclient.ClientID); err != nil {
|
||||
logger.Log(0, "failed to associate client", extclient.ClientID, "to user", userID)
|
||||
}
|
||||
extclient.OwnerID = userID
|
||||
if err := logic.SaveExtClient(&extclient); err != nil {
|
||||
logger.Log(0, "failed to add owner id", userID, "to client", extclient.ClientID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("created extclient", "user", r.Header.Get("user"), "network", node.Network, "clientid", extclient.ClientID)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
go func() {
|
||||
|
@ -431,12 +452,21 @@ 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"))
|
||||
|
@ -448,31 +478,12 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
// == PRO ==
|
||||
//networkName := params["network"]
|
||||
var changedID = update.ClientID != oldExtClient.ClientID
|
||||
if r.Header.Get("ismaster") != "yes" {
|
||||
userID := r.Header.Get("user")
|
||||
_, doesOwn := doesUserOwnClient(userID, params["clientid"], oldExtClient.Network)
|
||||
if !doesOwn {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("user not permitted"), "internal"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if changedID && oldExtClient.OwnerID != "" {
|
||||
if err := pro.DissociateNetworkUserClient(oldExtClient.OwnerID, oldExtClient.Network, oldExtClient.ClientID); err != nil {
|
||||
logger.Log(0, "failed to dissociate client", oldExtClient.ClientID, "from user", oldExtClient.OwnerID)
|
||||
}
|
||||
if err := pro.AssociateNetworkUserClient(oldExtClient.OwnerID, oldExtClient.Network, update.ClientID); err != nil {
|
||||
logger.Log(0, "failed to associate client", update.ClientID, "to user", oldExtClient.OwnerID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(update.DeniedACLs) != len(oldExtClient.DeniedACLs) {
|
||||
sendPeerUpdate = true
|
||||
logic.SetClientACLs(&oldExtClient, update.DeniedACLs)
|
||||
}
|
||||
// == END PRO ==
|
||||
|
||||
if update.Enabled != oldExtClient.Enabled {
|
||||
sendPeerUpdate = true
|
||||
|
@ -535,6 +546,12 @@ 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("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
|
||||
}
|
||||
ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
|
@ -543,24 +560,6 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// == PRO ==
|
||||
if r.Header.Get("ismaster") != "yes" {
|
||||
userID, clientID, networkName := r.Header.Get("user"), params["clientid"], params["network"]
|
||||
_, doesOwn := doesUserOwnClient(userID, clientID, networkName)
|
||||
if !doesOwn {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("user not permitted"), "internal"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if extclient.OwnerID != "" {
|
||||
if err = pro.DissociateNetworkUserClient(extclient.OwnerID, extclient.Network, extclient.ClientID); err != nil {
|
||||
logger.Log(0, "failed to dissociate client", extclient.ClientID, "from user", extclient.OwnerID)
|
||||
}
|
||||
}
|
||||
|
||||
// == END PRO ==
|
||||
|
||||
err = logic.DeleteExtClient(params["network"], params["clientid"])
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
|
@ -584,63 +583,6 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnSuccessResponse(w, r, params["clientid"]+" deleted.")
|
||||
}
|
||||
|
||||
func checkProClientAccess(username, clientID string, network *models.Network) (bool, error) {
|
||||
u, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if u.IsAdmin {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
netUser, err := pro.GetNetworkUser(network.NetID, promodels.NetworkUserID(u.UserName))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if netUser.AccessLevel == pro.NET_ADMIN {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if netUser.AccessLevel == pro.NO_ACCESS {
|
||||
return false, fmt.Errorf("user does not have access")
|
||||
}
|
||||
|
||||
if !(len(netUser.Clients) < netUser.ClientLimit) {
|
||||
return false, fmt.Errorf("user can not create more clients")
|
||||
}
|
||||
|
||||
if netUser.AccessLevel < pro.NO_ACCESS {
|
||||
netUser.Clients = append(netUser.Clients, clientID)
|
||||
if err = pro.UpdateNetworkUser(network.NetID, netUser); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// checks if net user owns an ext client or is an admin
|
||||
func doesUserOwnClient(username, clientID, network string) (bool, bool) {
|
||||
u, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
return false, false
|
||||
}
|
||||
if u.IsAdmin {
|
||||
return true, true
|
||||
}
|
||||
|
||||
netUser, err := pro.GetNetworkUser(network, promodels.NetworkUserID(u.UserName))
|
||||
if err != nil {
|
||||
return false, false
|
||||
}
|
||||
|
||||
if netUser.AccessLevel == pro.NET_ADMIN {
|
||||
return false, true
|
||||
}
|
||||
|
||||
return false, logic.StringSliceContains(netUser.Clients, clientID)
|
||||
}
|
||||
|
||||
// validateCustomExtClient Validates the extclient object
|
||||
func validateCustomExtClient(customExtClient *models.CustomExtClient, checkID bool) error {
|
||||
//validate clientid
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
)
|
||||
|
||||
func hostHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/hosts", logic.SecurityCheck(false, http.HandlerFunc(getHosts))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).Methods(http.MethodPost)
|
||||
|
|
|
@ -20,9 +20,9 @@ import (
|
|||
)
|
||||
|
||||
func networkHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/networks", logic.SecurityCheck(false, http.HandlerFunc(getNetworks))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/networks", logic.SecurityCheck(true, http.HandlerFunc(getNetworks))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceNetworks, http.HandlerFunc(createNetwork)))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(false, http.HandlerFunc(getNetwork))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(getNetwork))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetwork))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).Methods(http.MethodPut)
|
||||
// ACLs
|
||||
|
@ -42,29 +42,14 @@ func networkHandlers(r *mux.Router) {
|
|||
// Responses:
|
||||
// 200: getNetworksSliceResponse
|
||||
func getNetworks(w http.ResponseWriter, r *http.Request) {
|
||||
networksSlice, marshalErr := getHeaderNetworks(r)
|
||||
if marshalErr != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "error unmarshalling networks: ",
|
||||
marshalErr.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(marshalErr, "badrequest"))
|
||||
return
|
||||
}
|
||||
allnetworks := []models.Network{}
|
||||
|
||||
var err error
|
||||
if len(networksSlice) > 0 && networksSlice[0] == logic.ALL_NETWORK_ACCESS {
|
||||
allnetworks, err = logic.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
logger.Log(0, r.Header.Get("user"), "failed to fetch networks: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
for _, network := range networksSlice {
|
||||
netObject, parentErr := logic.GetParentNetwork(network)
|
||||
if parentErr == nil {
|
||||
allnetworks = append(allnetworks, netObject)
|
||||
}
|
||||
}
|
||||
|
||||
allnetworks, err := logic.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
slog.Error("failed to fetch networks", "error", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
logger.Log(2, r.Header.Get("user"), "fetched networks.")
|
||||
|
@ -326,8 +311,7 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
// partial update
|
||||
netOld2 := netOld1
|
||||
netOld2.ProSettings = payload.ProSettings
|
||||
_, _, _, _, _, err = logic.UpdateNetwork(&netOld1, &netOld2)
|
||||
_, _, _, err = logic.UpdateNetwork(&netOld1, &netOld2)
|
||||
if err != nil {
|
||||
slog.Info("failed to update network", "user", r.Header.Get("user"), "err", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
|
|
|
@ -25,12 +25,10 @@ var netHost models.Host
|
|||
func TestMain(m *testing.M) {
|
||||
database.InitializeDatabase()
|
||||
defer database.CloseDB()
|
||||
logic.CreateAdmin(&models.User{
|
||||
logic.CreateSuperAdmin(&models.User{
|
||||
UserName: "admin",
|
||||
Password: "password",
|
||||
IsAdmin: true,
|
||||
Networks: []string{},
|
||||
Groups: []string{},
|
||||
})
|
||||
peerUpdate := make(chan *models.Node)
|
||||
go logic.ManageZombies(context.Background(), peerUpdate)
|
||||
|
@ -91,27 +89,16 @@ func TestSecurityCheck(t *testing.T) {
|
|||
|
||||
os.Setenv("MASTER_KEY", "secretkey")
|
||||
t.Run("NoNetwork", func(t *testing.T) {
|
||||
networks, username, err := logic.UserPermissions(false, "", "Bearer secretkey")
|
||||
username, err := logic.UserPermissions(false, "Bearer secretkey")
|
||||
assert.Nil(t, err)
|
||||
t.Log(networks, username)
|
||||
})
|
||||
t.Run("WithNetwork", func(t *testing.T) {
|
||||
networks, username, err := logic.UserPermissions(false, "skynet", "Bearer secretkey")
|
||||
assert.Nil(t, err)
|
||||
t.Log(networks, username)
|
||||
})
|
||||
t.Run("BadNet", func(t *testing.T) {
|
||||
t.Skip()
|
||||
networks, username, err := logic.UserPermissions(false, "badnet", "Bearer secretkey")
|
||||
assert.NotNil(t, err)
|
||||
t.Log(err)
|
||||
t.Log(networks, username)
|
||||
t.Log(username)
|
||||
})
|
||||
|
||||
t.Run("BadToken", func(t *testing.T) {
|
||||
networks, username, err := logic.UserPermissions(false, "skynet", "Bearer badkey")
|
||||
username, err := logic.UserPermissions(false, "Bearer badkey")
|
||||
assert.NotNil(t, err)
|
||||
t.Log(err)
|
||||
t.Log(networks, username)
|
||||
t.Log(username)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,7 @@ import (
|
|||
"github.com/gravitl/netmaker/database"
|
||||
"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"
|
||||
"github.com/gravitl/netmaker/mq"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
@ -26,13 +24,12 @@ func nodeHandlers(r *mux.Router) {
|
|||
r.HandleFunc("/api/nodes", Authorize(false, false, "user", http.HandlerFunc(getAllNodes))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/nodes/{network}", Authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}", logic.SecurityCheck(true, http.HandlerFunc(updateNode))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", Authorize(false, true, "user", checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).Methods(http.MethodPost)
|
||||
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}/deleteingress", 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}/creategateway", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", logic.SecurityCheck(true, http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(true, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost)
|
||||
}
|
||||
|
@ -198,23 +195,18 @@ func Authorize(hostAllowed, networkCheck bool, authNetwork string, next http.Han
|
|||
|
||||
var isAuthorized = false
|
||||
var nodeID = ""
|
||||
username, networks, isadmin, errN := logic.VerifyUserToken(authToken)
|
||||
username, issuperadmin, isadmin, errN := logic.VerifyUserToken(authToken)
|
||||
if errN != nil {
|
||||
logic.ReturnErrorResponse(w, r, errorResponse)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errN, logic.Unauthorized_Msg))
|
||||
return
|
||||
}
|
||||
|
||||
isnetadmin := isadmin
|
||||
if errN == nil && isadmin {
|
||||
isnetadmin := issuperadmin || isadmin
|
||||
if errN == nil && (issuperadmin || isadmin) {
|
||||
nodeID = "mastermac"
|
||||
isAuthorized = true
|
||||
r.Header.Set("ismasterkey", "yes")
|
||||
}
|
||||
if !isadmin && params["network"] != "" {
|
||||
if logic.StringSliceContains(networks, params["network"]) && pro.IsUserNetAdmin(params["network"], username) {
|
||||
isnetadmin = true
|
||||
}
|
||||
}
|
||||
//The mastermac (login with masterkey from config) can do everything!! May be dangerous.
|
||||
if nodeID == "mastermac" {
|
||||
isAuthorized = true
|
||||
|
@ -326,14 +318,6 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
nodes, err = getUsersNodes(*user)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
"error fetching nodes: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
}
|
||||
// return all the nodes in JSON/API format
|
||||
apiNodes := logic.GetAllNodesAPI(nodes[:])
|
||||
|
@ -343,19 +327,6 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(apiNodes)
|
||||
}
|
||||
|
||||
func getUsersNodes(user models.User) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
var err error
|
||||
for _, networkName := range user.Networks {
|
||||
tmpNodes, err := logic.GetNetworkNodes(networkName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
nodes = append(nodes, tmpNodes...)
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
// swagger:route GET /api/nodes/{network}/{nodeid} nodes getNode
|
||||
//
|
||||
// Get an individual node.
|
||||
|
@ -727,13 +698,6 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
forceDelete := r.URL.Query().Get("force") == "true"
|
||||
fromNode := r.Header.Get("requestfrom") == "node"
|
||||
if r.Header.Get("ismaster") != "yes" {
|
||||
username := r.Header.Get("user")
|
||||
if username != "" && !doesUserOwnNode(username, params["network"], nodeid) {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("user not permitted"), "badrequest"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if node.IsRelayed {
|
||||
// cleanup node from relayednodes on relay node
|
||||
relayNode, err := logic.GetNodeByID(node.RelayedBy)
|
||||
|
@ -780,27 +744,6 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
|
|||
}()
|
||||
}
|
||||
|
||||
func doesUserOwnNode(username, network, nodeID string) bool {
|
||||
u, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if u.IsAdmin {
|
||||
return true
|
||||
}
|
||||
|
||||
netUser, err := pro.GetNetworkUser(network, promodels.NetworkUserID(u.UserName))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if netUser.AccessLevel == pro.NET_ADMIN {
|
||||
return true
|
||||
}
|
||||
|
||||
return logic.StringSliceContains(netUser.Nodes, nodeID)
|
||||
}
|
||||
|
||||
func validateParams(nodeid, netid string) (models.Node, error) {
|
||||
node, err := logic.GetNodeByID(nodeid)
|
||||
if err != nil {
|
||||
|
|
|
@ -13,23 +13,19 @@ import (
|
|||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
var (
|
||||
upgrader = websocket.Upgrader{}
|
||||
)
|
||||
|
||||
// verifyJWT makes logic.VerifyJWT fakeable/mockable in tests
|
||||
var verifyJWT = logic.VerifyJWT
|
||||
|
||||
func userHandlers(r *mux.Router) {
|
||||
|
||||
r.HandleFunc("/api/users/adm/hasadmin", hasAdmin).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/users/adm/createadmin", createAdmin).Methods(http.MethodPost)
|
||||
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/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(updateUser)))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/users/networks/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUserNetworks))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/users/{username}/adm", logic.SecurityCheck(true, http.HandlerFunc(updateUserAdm))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
|
||||
|
@ -112,7 +108,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
|
|||
response.Write(successJSONResponse)
|
||||
}
|
||||
|
||||
// swagger:route GET /api/users/adm/hasadmin user hasAdmin
|
||||
// swagger:route GET /api/users/adm/hassuperadmin user hasSuperAdmin
|
||||
//
|
||||
// Checks whether the server has an admin.
|
||||
//
|
||||
|
@ -123,18 +119,18 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
|
|||
//
|
||||
// Responses:
|
||||
// 200: successResponse
|
||||
func hasAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
func hasSuperAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
hasadmin, err := logic.HasAdmin()
|
||||
hasSuperAdmin, err := logic.HasSuperAdmin()
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to check for admin: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(hasadmin)
|
||||
json.NewEncoder(w).Encode(hasSuperAdmin)
|
||||
|
||||
}
|
||||
|
||||
|
@ -194,7 +190,7 @@ func getUsers(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(users)
|
||||
}
|
||||
|
||||
// swagger:route POST /api/users/adm/createadmin user createAdmin
|
||||
// swagger:route POST /api/users/adm/createsuperadmin user createAdmin
|
||||
//
|
||||
// Make a user an admin.
|
||||
//
|
||||
|
@ -205,16 +201,14 @@ func getUsers(w http.ResponseWriter, r *http.Request) {
|
|||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func createAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
var admin models.User
|
||||
var u models.User
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&admin)
|
||||
err := json.NewDecoder(r.Body).Decode(&u)
|
||||
if err != nil {
|
||||
|
||||
logger.Log(0, admin.UserName, "error decoding request body: ",
|
||||
err.Error())
|
||||
slog.Error("error decoding request body", "error", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
|
@ -224,16 +218,72 @@ func createAdmin(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err = logic.CreateAdmin(&admin)
|
||||
err = logic.CreateSuperAdmin(&u)
|
||||
if err != nil {
|
||||
logger.Log(0, admin.UserName, "failed to create admin: ",
|
||||
err.Error())
|
||||
slog.Error("failed to create admin", "error", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
logger.Log(1, u.UserName, "was made a super admin")
|
||||
json.NewEncoder(w).Encode(logic.ToReturnUser(u))
|
||||
}
|
||||
|
||||
logger.Log(1, admin.UserName, "was made a new admin")
|
||||
json.NewEncoder(w).Encode(logic.ToReturnUser(admin))
|
||||
// swagger:route POST /api/users/adm/transfersuperadmin user transferSuperAdmin
|
||||
//
|
||||
// Transfers superadmin 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 params = mux.Vars(r)
|
||||
username := params["username"]
|
||||
u, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
slog.Error("error getting user", "user", u.UserName, "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
|
||||
|
@ -249,83 +299,41 @@ func createAdmin(w http.ResponseWriter, r *http.Request) {
|
|||
// 200: userBodyResponse
|
||||
func createUser(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"))
|
||||
}
|
||||
var user models.User
|
||||
err := json.NewDecoder(r.Body).Decode(&user)
|
||||
err = json.NewDecoder(r.Body).Decode(&user)
|
||||
if err != nil {
|
||||
logger.Log(0, user.UserName, "error decoding request body: ",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
if !caller.IsSuperAdmin && user.IsAdmin {
|
||||
err = errors.New("only superadmin can create admin users")
|
||||
slog.Error("error creating new user: ", "user", user.UserName, "error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
|
||||
return
|
||||
}
|
||||
if user.IsSuperAdmin {
|
||||
err = errors.New("additional superadmins cannot be created")
|
||||
slog.Error("error creating new user: ", "user", user.UserName, "error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
err = logic.CreateUser(&user)
|
||||
if err != nil {
|
||||
logger.Log(0, user.UserName, "error creating new user: ",
|
||||
err.Error())
|
||||
slog.Error("error creating new user: ", "user", user.UserName, "error", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
logger.Log(1, user.UserName, "was created")
|
||||
slog.Info("user was created", "username", user.UserName)
|
||||
json.NewEncoder(w).Encode(logic.ToReturnUser(user))
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/users/networks/{username} user updateUserNetworks
|
||||
//
|
||||
// Updates the networks of the given user.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
// start here
|
||||
username := params["username"]
|
||||
user, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
logger.Log(0, username,
|
||||
"failed to update user networks: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
userChange := &models.User{}
|
||||
// we decode our body request params
|
||||
err = json.NewDecoder(r.Body).Decode(userChange)
|
||||
if err != nil {
|
||||
logger.Log(0, username, "error decoding request body: ",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = logic.UpdateUserNetworks(userChange.Networks, userChange.Groups, userChange.IsAdmin, &models.ReturnUser{
|
||||
Groups: user.Groups,
|
||||
IsAdmin: user.IsAdmin,
|
||||
Networks: user.Networks,
|
||||
UserName: user.UserName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Log(0, username,
|
||||
"failed to update user networks: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
logger.Log(1, username, "status was updated")
|
||||
// re-read and return the new user struct
|
||||
returnUser, err := logic.GetReturnUser(username)
|
||||
if err != nil {
|
||||
logger.Log(0, username, "failed to fetch user: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(returnUser)
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/users/{username} user updateUser
|
||||
//
|
||||
// Update a user.
|
||||
|
@ -341,18 +349,19 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
// start here
|
||||
jwtUser, _, isadmin, err := verifyJWT(r.Header.Get("Authorization"))
|
||||
if err != nil {
|
||||
logger.Log(0, "verifyJWT error", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
var caller *models.User
|
||||
var err error
|
||||
var ismaster bool
|
||||
if r.Header.Get("user") == logic.MasterUser {
|
||||
ismaster = true
|
||||
} else {
|
||||
caller, err = logic.GetUser(r.Header.Get("user"))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
}
|
||||
}
|
||||
|
||||
username := params["username"]
|
||||
if username != jwtUser && !isadmin {
|
||||
logger.Log(0, "non-admin user", jwtUser, "attempted to update user", username)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not authorizied"), "unauthorized"))
|
||||
return
|
||||
}
|
||||
user, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
logger.Log(0, username,
|
||||
|
@ -360,27 +369,70 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
var userchange models.User
|
||||
// we decode our body request params
|
||||
err = json.NewDecoder(r.Body).Decode(&userchange)
|
||||
if err != nil {
|
||||
slog.Error("failed to decode body", "error ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
if user.UserName != userchange.UserName {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user in param and request body not matching"), "badrequest"))
|
||||
return
|
||||
}
|
||||
selfUpdate := false
|
||||
if !ismaster && caller.UserName == user.UserName {
|
||||
selfUpdate = true
|
||||
}
|
||||
|
||||
if !ismaster && !selfUpdate {
|
||||
if caller.IsAdmin && user.IsSuperAdmin {
|
||||
slog.Error("non-superadmin user", "caller", caller.UserName, "attempted to update superadmin user", username)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
|
||||
return
|
||||
}
|
||||
if !caller.IsAdmin && !caller.IsSuperAdmin {
|
||||
slog.Error("operation not allowed", "caller", caller.UserName, "attempted to update user", username)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
|
||||
return
|
||||
}
|
||||
if caller.IsAdmin && user.IsAdmin {
|
||||
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"))
|
||||
return
|
||||
}
|
||||
if caller.IsAdmin && userchange.IsAdmin {
|
||||
err = errors.New("admin user cannot update role of an another user to admin")
|
||||
slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
if !ismaster && selfUpdate {
|
||||
if user.IsAdmin != userchange.IsAdmin || user.IsSuperAdmin != userchange.IsSuperAdmin {
|
||||
slog.Error("user cannot change his own role", "caller", caller.UserName, "attempted to update user role", username)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"))
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
if ismaster {
|
||||
if !user.IsSuperAdmin && userchange.IsSuperAdmin {
|
||||
slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if auth.IsOauthUser(user) == nil {
|
||||
err := fmt.Errorf("cannot update user info for oauth user %s", username)
|
||||
logger.Log(0, err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
|
||||
return
|
||||
}
|
||||
var userchange models.User
|
||||
// we decode our body request params
|
||||
err = json.NewDecoder(r.Body).Decode(&userchange)
|
||||
if err != nil {
|
||||
logger.Log(0, username, "error decoding request body: ",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
if userchange.IsAdmin && !isadmin {
|
||||
logger.Log(0, "non-admin user", jwtUser, "attempted get admin privilages")
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not authorizied"), "unauthorized"))
|
||||
return
|
||||
}
|
||||
userchange.Networks = nil
|
||||
|
||||
user, err = logic.UpdateUser(&userchange, user)
|
||||
if err != nil {
|
||||
logger.Log(0, username,
|
||||
|
@ -392,57 +444,6 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/users/{username}/adm user updateUserAdm
|
||||
//
|
||||
// Updates the given admin user's info (as long as the user is an admin).
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func updateUserAdm(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
// start here
|
||||
username := params["username"]
|
||||
user, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if auth.IsOauthUser(user) == nil {
|
||||
err := fmt.Errorf("cannot update user info for oauth user %s", username)
|
||||
logger.Log(0, err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
|
||||
return
|
||||
}
|
||||
var userchange models.User
|
||||
// we decode our body request params
|
||||
err = json.NewDecoder(r.Body).Decode(&userchange)
|
||||
if err != nil {
|
||||
logger.Log(0, username, "error decoding request body: ",
|
||||
err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
if !user.IsAdmin {
|
||||
logger.Log(0, username, "not an admin user")
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not a admin user"), "badrequest"))
|
||||
}
|
||||
user, err = logic.UpdateUser(&userchange, user)
|
||||
if err != nil {
|
||||
logger.Log(0, username,
|
||||
"failed to update user (admin) info: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
logger.Log(1, username, "was updated (admin)")
|
||||
json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/users/{username} user deleteUser
|
||||
//
|
||||
// Delete a user.
|
||||
|
@ -460,9 +461,32 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// get params
|
||||
var params = mux.Vars(r)
|
||||
|
||||
caller, err := logic.GetUser(r.Header.Get("user"))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
}
|
||||
username := params["username"]
|
||||
|
||||
user, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
logger.Log(0, username,
|
||||
"failed to update user info: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if user.IsSuperAdmin {
|
||||
slog.Error(
|
||||
"failed to delete user: ", "user", username, "error", "superadmin cannot be deleted")
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if !caller.IsSuperAdmin {
|
||||
if caller.IsAdmin && user.IsAdmin {
|
||||
slog.Error(
|
||||
"failed to delete user: ", "user", username, "error", "admin cannot delete another admin user")
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
}
|
||||
success, err := logic.DeleteUser(username)
|
||||
if err != nil {
|
||||
logger.Log(0, username,
|
||||
|
@ -495,14 +519,3 @@ func socketHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// Start handling the session
|
||||
go auth.SessionHandler(conn)
|
||||
}
|
||||
|
||||
// getHeaderNetworks returns a slice of networks parsed form the request header.
|
||||
func getHeaderNetworks(r *http.Request) ([]string, error) {
|
||||
headerNetworks := r.Header.Get("networks")
|
||||
networksSlice := []string{}
|
||||
err := json.Unmarshal([]byte(headerNetworks), &networksSlice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return networksSlice, nil
|
||||
}
|
||||
|
|
|
@ -2,13 +2,14 @@ package controller
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/go-jose/go-jose/v3/json"
|
||||
"github.com/gorilla/mux"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-jose/go-jose/v3/json"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
|
@ -47,72 +48,10 @@ func TestCreateAdminNoHashedPassword(t *testing.T) {
|
|||
rec, req := prepareUserRequest(t, user, "")
|
||||
|
||||
// test response
|
||||
createAdmin(rec, req)
|
||||
createSuperAdmin(rec, req)
|
||||
assertUserNameButNoPassword(t, rec.Body, user.UserName)
|
||||
}
|
||||
|
||||
func TestCreateUserNoHashedPassword(t *testing.T) {
|
||||
// prepare existing user base
|
||||
deleteAllUsers(t)
|
||||
|
||||
// prepare request
|
||||
user := models.User{UserName: "jonathan", Password: "password"}
|
||||
rec, req := prepareUserRequest(t, user, "")
|
||||
|
||||
// test response
|
||||
createUser(rec, req)
|
||||
assertUserNameButNoPassword(t, rec.Body, user.UserName)
|
||||
}
|
||||
|
||||
func TestUpdateUserNetworksNoHashedPassword(t *testing.T) {
|
||||
// prepare existing user base
|
||||
user1 := models.User{UserName: "joestar", Password: "jonathan"}
|
||||
haveOnlyOneUser(t, user1)
|
||||
|
||||
// prepare request
|
||||
user2 := models.User{UserName: "joestar", Password: "joseph"}
|
||||
rec, req := prepareUserRequest(t, user2, user1.UserName)
|
||||
|
||||
// test response
|
||||
updateUserNetworks(rec, req)
|
||||
assertUserNameButNoPassword(t, rec.Body, user1.UserName)
|
||||
}
|
||||
|
||||
func TestUpdateUserNoHashedPassword(t *testing.T) {
|
||||
// prepare existing user base
|
||||
user1 := models.User{UserName: "dio", Password: "brando"}
|
||||
haveOnlyOneUser(t, user1)
|
||||
|
||||
// prepare request
|
||||
user2 := models.User{UserName: "giorno", Password: "giovanna"}
|
||||
rec, req := prepareUserRequest(t, user2, user1.UserName)
|
||||
|
||||
// mock the jwt verification
|
||||
oldVerify := verifyJWT
|
||||
verifyJWT = func(bearerToken string) (username string, networks []string, isadmin bool, err error) {
|
||||
return user1.UserName, user1.Networks, user1.IsAdmin, nil
|
||||
}
|
||||
defer func() { verifyJWT = oldVerify }()
|
||||
|
||||
// test response
|
||||
updateUser(rec, req)
|
||||
assertUserNameButNoPassword(t, rec.Body, user2.UserName)
|
||||
}
|
||||
|
||||
func TestUpdateUserAdmNoHashedPassword(t *testing.T) {
|
||||
// prepare existing user base
|
||||
user1 := models.User{UserName: "dio", Password: "brando", IsAdmin: true}
|
||||
haveOnlyOneUser(t, user1)
|
||||
|
||||
// prepare request
|
||||
user2 := models.User{UserName: "giorno", Password: "giovanna"}
|
||||
rec, req := prepareUserRequest(t, user2, user1.UserName)
|
||||
|
||||
// test response
|
||||
updateUserAdm(rec, req)
|
||||
assertUserNameButNoPassword(t, rec.Body, user2.UserName)
|
||||
}
|
||||
|
||||
func prepareUserRequest(t *testing.T, userForBody models.User, userNameForParam string) (*httptest.ResponseRecorder, *http.Request) {
|
||||
bits, err := json.Marshal(userForBody)
|
||||
assert.Nil(t, err)
|
||||
|
@ -120,14 +59,15 @@ func prepareUserRequest(t *testing.T, userForBody models.User, userNameForParam
|
|||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("ANY", "https://example.com", body) // only the body matters here
|
||||
req = mux.SetURLVars(req, map[string]string{"username": userNameForParam})
|
||||
req.Header.Set("user", userForBody.UserName)
|
||||
return rec, req
|
||||
}
|
||||
|
||||
func haveOnlyOneUser(t *testing.T, user models.User) {
|
||||
deleteAllUsers(t)
|
||||
var err error
|
||||
if user.IsAdmin {
|
||||
err = logic.CreateAdmin(&user)
|
||||
if user.IsSuperAdmin {
|
||||
err = logic.CreateSuperAdmin(&user)
|
||||
} else {
|
||||
err = logic.CreateUser(&user)
|
||||
}
|
||||
|
@ -142,7 +82,7 @@ func assertUserNameButNoPassword(t *testing.T, r io.Reader, userName string) {
|
|||
assert.Empty(t, resp.Password)
|
||||
}
|
||||
|
||||
func TestHasAdmin(t *testing.T) {
|
||||
func TestHasSuperAdmin(t *testing.T) {
|
||||
// delete all current users
|
||||
users, _ := logic.GetUsers()
|
||||
for _, user := range users {
|
||||
|
@ -151,31 +91,31 @@ func TestHasAdmin(t *testing.T) {
|
|||
assert.True(t, success)
|
||||
}
|
||||
t.Run("NoUser", func(t *testing.T) {
|
||||
found, err := logic.HasAdmin()
|
||||
found, err := logic.HasSuperAdmin()
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, found)
|
||||
})
|
||||
t.Run("No admin user", func(t *testing.T) {
|
||||
var user = models.User{UserName: "noadmin", Password: "password"}
|
||||
t.Run("No superadmin user", func(t *testing.T) {
|
||||
var user = models.User{UserName: "nosuperadmin", Password: "password"}
|
||||
err := logic.CreateUser(&user)
|
||||
assert.Nil(t, err)
|
||||
found, err := logic.HasAdmin()
|
||||
found, err := logic.HasSuperAdmin()
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, found)
|
||||
})
|
||||
t.Run("admin user", func(t *testing.T) {
|
||||
var user = models.User{UserName: "admin", Password: "password", IsAdmin: true}
|
||||
t.Run("superadmin user", func(t *testing.T) {
|
||||
var user = models.User{UserName: "superadmin", Password: "password", IsSuperAdmin: true}
|
||||
err := logic.CreateUser(&user)
|
||||
assert.Nil(t, err)
|
||||
found, err := logic.HasAdmin()
|
||||
found, err := logic.HasSuperAdmin()
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, found)
|
||||
})
|
||||
t.Run("multiple admins", func(t *testing.T) {
|
||||
var user = models.User{UserName: "admin1", Password: "password", IsAdmin: true}
|
||||
t.Run("multiple superadmins", func(t *testing.T) {
|
||||
var user = models.User{UserName: "superadmin1", Password: "password", IsSuperAdmin: true}
|
||||
err := logic.CreateUser(&user)
|
||||
assert.Nil(t, err)
|
||||
found, err := logic.HasAdmin()
|
||||
found, err := logic.HasSuperAdmin()
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, found)
|
||||
})
|
||||
|
@ -195,20 +135,20 @@ func TestCreateUser(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestCreateAdmin(t *testing.T) {
|
||||
func TestCreateSuperAdmin(t *testing.T) {
|
||||
deleteAllUsers(t)
|
||||
var user models.User
|
||||
t.Run("NoAdmin", func(t *testing.T) {
|
||||
t.Run("NoSuperAdmin", func(t *testing.T) {
|
||||
user.UserName = "admin"
|
||||
user.Password = "password"
|
||||
err := logic.CreateAdmin(&user)
|
||||
err := logic.CreateSuperAdmin(&user)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
t.Run("AdminExists", func(t *testing.T) {
|
||||
t.Run("SuperAdminExists", func(t *testing.T) {
|
||||
user.UserName = "admin2"
|
||||
user.Password = "password1"
|
||||
err := logic.CreateAdmin(&user)
|
||||
assert.EqualError(t, err, "admin user already exists")
|
||||
err := logic.CreateSuperAdmin(&user)
|
||||
assert.EqualError(t, err, "superadmin user already exists")
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -280,7 +220,7 @@ func TestValidateUser(t *testing.T) {
|
|||
func TestGetUser(t *testing.T) {
|
||||
deleteAllUsers(t)
|
||||
|
||||
user := models.User{UserName: "admin", Password: "password", Networks: nil, IsAdmin: true, Groups: nil}
|
||||
user := models.User{UserName: "admin", Password: "password", IsAdmin: true}
|
||||
|
||||
t.Run("NonExistantUser", func(t *testing.T) {
|
||||
admin, err := logic.GetUser("admin")
|
||||
|
@ -338,7 +278,7 @@ func TestGetUsers(t *testing.T) {
|
|||
func TestUpdateUser(t *testing.T) {
|
||||
deleteAllUsers(t)
|
||||
user := models.User{UserName: "admin", Password: "password", IsAdmin: true}
|
||||
newuser := models.User{UserName: "hello", Password: "world", Networks: []string{"wirecat, netmaker"}, IsAdmin: true, Groups: []string{}}
|
||||
newuser := models.User{UserName: "hello", Password: "world", IsAdmin: true}
|
||||
t.Run("NonExistantUser", func(t *testing.T) {
|
||||
admin, err := logic.UpdateUser(&newuser, &user)
|
||||
assert.EqualError(t, err, "could not find any records")
|
||||
|
@ -381,7 +321,7 @@ func TestUpdateUser(t *testing.T) {
|
|||
|
||||
func TestVerifyAuthRequest(t *testing.T) {
|
||||
deleteAllUsers(t)
|
||||
user := models.User{UserName: "admin", Password: "password", Networks: nil, IsAdmin: true, Groups: nil}
|
||||
user := models.User{UserName: "admin", Password: "password", IsSuperAdmin: false, IsAdmin: true}
|
||||
var authRequest models.UserAuthParams
|
||||
t.Run("EmptyUserName", func(t *testing.T) {
|
||||
authRequest.UserName = ""
|
||||
|
@ -402,7 +342,7 @@ func TestVerifyAuthRequest(t *testing.T) {
|
|||
authRequest.Password = "password"
|
||||
jwt, err := logic.VerifyAuthRequest(authRequest)
|
||||
assert.Equal(t, "", jwt)
|
||||
assert.EqualError(t, err, "error retrieving user from db: could not find any records")
|
||||
assert.EqualError(t, err, "incorrect credentials")
|
||||
})
|
||||
t.Run("Non-Admin", func(t *testing.T) {
|
||||
user.IsAdmin = false
|
||||
|
@ -417,7 +357,7 @@ func TestVerifyAuthRequest(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
})
|
||||
t.Run("WrongPassword", func(t *testing.T) {
|
||||
user := models.User{UserName: "admin", Password: "password", Groups: []string{}}
|
||||
user := models.User{UserName: "admin", Password: "password"}
|
||||
if err := logic.CreateUser(&user); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
|
@ -25,12 +25,10 @@ var (
|
|||
func TestMain(m *testing.M) {
|
||||
database.InitializeDatabase()
|
||||
defer database.CloseDB()
|
||||
logic.CreateAdmin(&models.User{
|
||||
UserName: "admin",
|
||||
Password: "password",
|
||||
IsAdmin: true,
|
||||
Networks: []string{},
|
||||
Groups: []string{},
|
||||
logic.CreateSuperAdmin(&models.User{
|
||||
UserName: "superadmin",
|
||||
Password: "password",
|
||||
IsSuperAdmin: true,
|
||||
})
|
||||
peerUpdate := make(chan *models.Node)
|
||||
go logic.ManageZombies(context.Background(), peerUpdate)
|
||||
|
|
206
logic/auth.go
206
logic/auth.go
|
@ -11,14 +11,11 @@ import (
|
|||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
// HasAdmin - checks if server has an admin
|
||||
func HasAdmin() (bool, error) {
|
||||
// HasSuperAdmin - checks if server has an superadmin/owner
|
||||
func HasSuperAdmin() (bool, error) {
|
||||
|
||||
collection, err := database.FetchRecords(database.USERS_TABLE_NAME)
|
||||
if err != nil {
|
||||
|
@ -34,7 +31,7 @@ func HasAdmin() (bool, error) {
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if user.IsAdmin {
|
||||
if user.IsSuperAdmin {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
@ -85,9 +82,8 @@ func CreateUser(user *models.User) error {
|
|||
// set password to encrypted password
|
||||
user.Password = string(hash)
|
||||
|
||||
tokenString, _ := CreateProUserJWT(user.UserName, user.Networks, user.Groups, user.IsAdmin)
|
||||
tokenString, _ := CreateUserJWT(user.UserName, user.IsSuperAdmin, user.IsAdmin)
|
||||
if tokenString == "" {
|
||||
// logic.ReturnErrorResponse(w, r, errorResponse)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -103,56 +99,20 @@ func CreateUser(user *models.User) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// == PRO == Add user to every network as network user ==
|
||||
currentNets, err := GetNetworks()
|
||||
if err != nil {
|
||||
currentNets = []models.Network{}
|
||||
}
|
||||
for i := range currentNets {
|
||||
newUser := promodels.NetworkUser{
|
||||
ID: promodels.NetworkUserID(user.UserName),
|
||||
Clients: []string{},
|
||||
Nodes: []string{},
|
||||
}
|
||||
|
||||
pro.AddProNetDefaults(¤tNets[i])
|
||||
if pro.IsUserAllowed(¤tNets[i], user.UserName, user.Groups) {
|
||||
newUser.AccessLevel = currentNets[i].ProSettings.DefaultAccessLevel
|
||||
newUser.ClientLimit = currentNets[i].ProSettings.DefaultUserClientLimit
|
||||
newUser.NodeLimit = currentNets[i].ProSettings.DefaultUserNodeLimit
|
||||
} else {
|
||||
newUser.AccessLevel = pro.NO_ACCESS
|
||||
newUser.ClientLimit = 0
|
||||
newUser.NodeLimit = 0
|
||||
}
|
||||
|
||||
// legacy
|
||||
if StringSliceContains(user.Networks, currentNets[i].NetID) {
|
||||
if !servercfg.IsPro {
|
||||
newUser.AccessLevel = pro.NET_ADMIN
|
||||
}
|
||||
}
|
||||
userErr := pro.CreateNetworkUser(¤tNets[i], &newUser)
|
||||
if userErr != nil {
|
||||
logger.Log(0, "failed to add network user data on network", currentNets[i].NetID, "for user", user.UserName)
|
||||
}
|
||||
}
|
||||
// == END PRO ==
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateAdmin - creates an admin user
|
||||
func CreateAdmin(admin *models.User) error {
|
||||
hasadmin, err := HasAdmin()
|
||||
// CreateSuperAdmin - creates an super admin user
|
||||
func CreateSuperAdmin(u *models.User) error {
|
||||
hassuperadmin, err := HasSuperAdmin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hasadmin {
|
||||
return errors.New("admin user already exists")
|
||||
if hassuperadmin {
|
||||
return errors.New("superadmin user already exists")
|
||||
}
|
||||
admin.IsAdmin = true
|
||||
return CreateUser(admin)
|
||||
u.IsSuperAdmin = true
|
||||
return CreateUser(u)
|
||||
}
|
||||
|
||||
// VerifyAuthRequest - verifies an auth request
|
||||
|
@ -166,7 +126,7 @@ func VerifyAuthRequest(authRequest models.UserAuthParams) (string, error) {
|
|||
// Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API until approved).
|
||||
record, err := database.FetchRecord(database.USERS_TABLE_NAME, authRequest.UserName)
|
||||
if err != nil {
|
||||
return "", errors.New("error retrieving user from db: " + err.Error())
|
||||
return "", errors.New("incorrect credentials")
|
||||
}
|
||||
if err = json.Unmarshal([]byte(record), &result); err != nil {
|
||||
return "", errors.New("error unmarshalling user json: " + err.Error())
|
||||
|
@ -180,65 +140,20 @@ func VerifyAuthRequest(authRequest models.UserAuthParams) (string, error) {
|
|||
}
|
||||
|
||||
// Create a new JWT for the node
|
||||
tokenString, _ := CreateProUserJWT(authRequest.UserName, result.Networks, result.Groups, result.IsAdmin)
|
||||
tokenString, _ := CreateUserJWT(authRequest.UserName, result.IsSuperAdmin, result.IsAdmin)
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
// UpdateUserNetworks - updates the networks of a given user
|
||||
func UpdateUserNetworks(newNetworks, newGroups []string, isadmin bool, currentUser *models.ReturnUser) error {
|
||||
// check if user exists
|
||||
returnedUser, err := GetUser(currentUser.UserName)
|
||||
// UpsertUser - updates user in the db
|
||||
func UpsertUser(user models.User) error {
|
||||
data, err := json.Marshal(&user)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if returnedUser.IsAdmin {
|
||||
return fmt.Errorf("can not make changes to an admin user, attempted to change %s", returnedUser.UserName)
|
||||
}
|
||||
if isadmin {
|
||||
currentUser.IsAdmin = true
|
||||
currentUser.Networks = nil
|
||||
} else {
|
||||
// == PRO ==
|
||||
currentUser.Groups = newGroups
|
||||
for _, n := range newNetworks {
|
||||
if !StringSliceContains(currentUser.Networks, n) {
|
||||
// make net admin of any network not previously assigned
|
||||
pro.MakeNetAdmin(n, currentUser.UserName)
|
||||
}
|
||||
}
|
||||
// Compare networks, find networks not in previous
|
||||
for _, n := range currentUser.Networks {
|
||||
if !StringSliceContains(newNetworks, n) {
|
||||
// if user was removed from a network, re-assign access to net default level
|
||||
if network, err := GetNetwork(n); err == nil {
|
||||
if network.ProSettings != nil {
|
||||
ok := pro.AssignAccessLvl(n, currentUser.UserName, network.ProSettings.DefaultAccessLevel)
|
||||
if ok {
|
||||
logger.Log(0, "changed", currentUser.UserName, "access level on network", network.NetID, "to", fmt.Sprintf("%d", network.ProSettings.DefaultAccessLevel))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := AdjustGroupPermissions(currentUser); err != nil {
|
||||
logger.Log(0, "failed to update user", currentUser.UserName, "after group update", err.Error())
|
||||
}
|
||||
// == END PRO ==
|
||||
|
||||
currentUser.Networks = newNetworks
|
||||
if err = database.Insert(user.UserName, string(data), database.USERS_TABLE_NAME); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userChange := models.User{
|
||||
UserName: currentUser.UserName,
|
||||
Networks: currentUser.Networks,
|
||||
IsAdmin: currentUser.IsAdmin,
|
||||
Password: "",
|
||||
Groups: currentUser.Groups,
|
||||
}
|
||||
|
||||
_, err = UpdateUser(&userChange, returnedUser)
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateUser - updates a given user
|
||||
|
@ -249,16 +164,13 @@ func UpdateUser(userchange, user *models.User) (*models.User, error) {
|
|||
}
|
||||
|
||||
queryUser := user.UserName
|
||||
|
||||
if userchange.UserName != "" {
|
||||
if userchange.UserName != "" && user.UserName != 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
|
||||
}
|
||||
if len(userchange.Networks) > 0 {
|
||||
user.Networks = userchange.Networks
|
||||
}
|
||||
if len(userchange.Groups) > 0 {
|
||||
user.Groups = userchange.Groups
|
||||
}
|
||||
if userchange.Password != "" {
|
||||
// encrypt that password so we never see it again
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(userchange.Password), 5)
|
||||
|
@ -271,10 +183,7 @@ func UpdateUser(userchange, user *models.User) (*models.User, error) {
|
|||
|
||||
user.Password = userchange.Password
|
||||
}
|
||||
|
||||
if (userchange.IsAdmin != user.IsAdmin) && !user.IsAdmin {
|
||||
user.IsAdmin = userchange.IsAdmin
|
||||
}
|
||||
user.IsAdmin = userchange.IsAdmin
|
||||
|
||||
err := ValidateUser(user)
|
||||
if err != nil {
|
||||
|
@ -326,23 +235,6 @@ func DeleteUser(user string) (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
|
||||
// == pro - remove user from all network user instances ==
|
||||
currentNets, err := GetNetworks()
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
currentNets = []models.Network{}
|
||||
} else {
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
|
||||
for i := range currentNets {
|
||||
netID := currentNets[i].NetID
|
||||
if err = pro.DeleteNetworkUser(netID, user); err != nil {
|
||||
logger.Log(0, "failed to remove", user, "as network user from network", netID, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
@ -414,51 +306,3 @@ func IsStateValid(state string) (string, bool) {
|
|||
func delState(state string) error {
|
||||
return database.DeleteRecord(database.SSO_STATE_CACHE, state)
|
||||
}
|
||||
|
||||
// PRO
|
||||
|
||||
// AdjustGroupPermissions - adjusts a given user's network access based on group changes
|
||||
func AdjustGroupPermissions(user *models.ReturnUser) error {
|
||||
networks, err := GetNetworks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// UPDATE
|
||||
// go through all networks and see if new group is in
|
||||
// if access level of current user is greater (value) than network's default
|
||||
// assign network's default
|
||||
// DELETE
|
||||
// if user not allowed on network a
|
||||
for i := range networks {
|
||||
AdjustNetworkUserPermissions(user, &networks[i])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AdjustNetworkUserPermissions - adjusts a given user's network access based on group changes
|
||||
func AdjustNetworkUserPermissions(user *models.ReturnUser, network *models.Network) error {
|
||||
networkUser, err := pro.GetNetworkUser(
|
||||
network.NetID,
|
||||
promodels.NetworkUserID(user.UserName),
|
||||
)
|
||||
if err == nil && network.ProSettings != nil {
|
||||
if pro.IsUserAllowed(network, user.UserName, user.Groups) {
|
||||
if networkUser.AccessLevel > network.ProSettings.DefaultAccessLevel {
|
||||
networkUser.AccessLevel = network.ProSettings.DefaultAccessLevel
|
||||
}
|
||||
if networkUser.NodeLimit < network.ProSettings.DefaultUserNodeLimit {
|
||||
networkUser.NodeLimit = network.ProSettings.DefaultUserNodeLimit
|
||||
}
|
||||
if networkUser.ClientLimit < network.ProSettings.DefaultUserClientLimit {
|
||||
networkUser.ClientLimit = network.ProSettings.DefaultUserClientLimit
|
||||
}
|
||||
} else {
|
||||
networkUser.AccessLevel = pro.NO_ACCESS
|
||||
networkUser.NodeLimit = 0
|
||||
networkUser.ClientLimit = 0
|
||||
}
|
||||
pro.UpdateNetworkUser(network.NetID, networkUser)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/exp/slices"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
|
@ -224,16 +223,3 @@ func getEnrollmentKeysMap() (map[string]*models.EnrollmentKey, error) {
|
|||
}
|
||||
return currentKeys, nil
|
||||
}
|
||||
|
||||
// UserHasNetworksAccess - checks if a user `u` has access to all `networks`
|
||||
func UserHasNetworksAccess(networks []string, u *models.User) bool {
|
||||
if u.IsAdmin {
|
||||
return true
|
||||
}
|
||||
for _, n := range networks {
|
||||
if !slices.Contains(u.Networks, n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -204,77 +204,3 @@ func TestDeTokenize_EnrollmentKeys(t *testing.T) {
|
|||
|
||||
removeAllEnrollments()
|
||||
}
|
||||
|
||||
func TestHasNetworksAccess(t *testing.T) {
|
||||
type Case struct {
|
||||
// network names
|
||||
n []string
|
||||
u models.User
|
||||
}
|
||||
pass := []Case{
|
||||
{
|
||||
n: []string{"n1", "n2"},
|
||||
u: models.User{
|
||||
Networks: []string{"n1", "n2"},
|
||||
IsAdmin: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
n: []string{"n1", "n2"},
|
||||
u: models.User{
|
||||
Networks: []string{},
|
||||
IsAdmin: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
n: []string{"n1", "n2"},
|
||||
u: models.User{
|
||||
Networks: []string{"n1", "n2", "n3"},
|
||||
IsAdmin: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
n: []string{"n2"},
|
||||
u: models.User{
|
||||
Networks: []string{"n2"},
|
||||
IsAdmin: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
deny := []Case{
|
||||
{
|
||||
n: []string{"n1", "n2"},
|
||||
u: models.User{
|
||||
Networks: []string{"n2"},
|
||||
IsAdmin: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
n: []string{"n1", "n2"},
|
||||
u: models.User{
|
||||
Networks: []string{},
|
||||
IsAdmin: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
n: []string{"n1", "n2"},
|
||||
u: models.User{
|
||||
Networks: []string{"n3"},
|
||||
IsAdmin: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
n: []string{"n2"},
|
||||
u: models.User{
|
||||
Networks: []string{"n1"},
|
||||
IsAdmin: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range pass {
|
||||
assert.True(t, UserHasNetworksAccess(tc.n, &tc.u))
|
||||
}
|
||||
for _, tc := range deny {
|
||||
assert.False(t, UserHasNetworksAccess(tc.n, &tc.u))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,6 +159,25 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq
|
|||
return node, err
|
||||
}
|
||||
|
||||
// GetIngressGwUsers - lists the users having to access to ingressGW
|
||||
func GetIngressGwUsers(node models.Node) (models.IngressGwUsers, error) {
|
||||
|
||||
gwUsers := models.IngressGwUsers{
|
||||
NodeID: node.ID.String(),
|
||||
Network: node.Network,
|
||||
}
|
||||
users, err := GetUsers()
|
||||
if err != nil {
|
||||
return gwUsers, err
|
||||
}
|
||||
for _, user := range users {
|
||||
if !user.IsAdmin && !user.IsSuperAdmin {
|
||||
gwUsers.Users = append(gwUsers.Users, user)
|
||||
}
|
||||
}
|
||||
return gwUsers, nil
|
||||
}
|
||||
|
||||
// DeleteIngressGateway - deletes an ingress gateway
|
||||
func DeleteIngressGateway(nodeid string) (models.Node, bool, []models.ExtClient, error) {
|
||||
removedClients := []models.ExtClient{}
|
||||
|
@ -210,3 +229,20 @@ func DeleteGatewayExtClients(gatewayID string, networkName string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsUserAllowedAccessToExtClient - checks if user has permission to access extclient
|
||||
func IsUserAllowedAccessToExtClient(username string, client models.ExtClient) bool {
|
||||
if username == MasterUser {
|
||||
return true
|
||||
}
|
||||
user, err := GetUser(username)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if !user.IsAdmin && !user.IsSuperAdmin {
|
||||
if user.UserName != client.OwnerID {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -52,37 +52,13 @@ func CreateJWT(uuid string, macAddress string, network string) (response string,
|
|||
return "", err
|
||||
}
|
||||
|
||||
// CreateProUserJWT - creates a user jwt token
|
||||
func CreateProUserJWT(username string, networks, groups []string, isadmin bool) (response string, err error) {
|
||||
expirationTime := time.Now().Add(60 * 12 * time.Minute)
|
||||
claims := &models.UserClaims{
|
||||
UserName: username,
|
||||
Networks: networks,
|
||||
IsAdmin: isadmin,
|
||||
Groups: groups,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: "Netmaker",
|
||||
Subject: fmt.Sprintf("user|%s", username),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(expirationTime),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
tokenString, err := token.SignedString(jwtSecretKey)
|
||||
if err == nil {
|
||||
return tokenString, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
// CreateUserJWT - creates a user jwt token
|
||||
func CreateUserJWT(username string, networks []string, isadmin bool) (response string, err error) {
|
||||
func CreateUserJWT(username string, issuperadmin, isadmin bool) (response string, err error) {
|
||||
expirationTime := time.Now().Add(60 * 12 * time.Minute)
|
||||
claims := &models.UserClaims{
|
||||
UserName: username,
|
||||
Networks: networks,
|
||||
IsAdmin: isadmin,
|
||||
UserName: username,
|
||||
IsSuperAdmin: issuperadmin,
|
||||
IsAdmin: isadmin,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: "Netmaker",
|
||||
Subject: fmt.Sprintf("user|%s", username),
|
||||
|
@ -100,23 +76,23 @@ func CreateUserJWT(username string, networks []string, isadmin bool) (response s
|
|||
}
|
||||
|
||||
// VerifyJWT verifies Auth Header
|
||||
func VerifyJWT(bearerToken string) (username string, networks []string, isadmin bool, err error) {
|
||||
func VerifyJWT(bearerToken string) (username string, issuperadmin, isadmin bool, err error) {
|
||||
token := ""
|
||||
tokenSplit := strings.Split(bearerToken, " ")
|
||||
if len(tokenSplit) > 1 {
|
||||
token = tokenSplit[1]
|
||||
} else {
|
||||
return "", nil, false, errors.New("invalid auth header")
|
||||
return "", false, false, errors.New("invalid auth header")
|
||||
}
|
||||
return VerifyUserToken(token)
|
||||
}
|
||||
|
||||
// VerifyUserToken func will used to Verify the JWT Token while using APIS
|
||||
func VerifyUserToken(tokenString string) (username string, networks []string, isadmin bool, err error) {
|
||||
func VerifyUserToken(tokenString string) (username string, issuperadmin, isadmin bool, err error) {
|
||||
claims := &models.UserClaims{}
|
||||
|
||||
if tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != "" {
|
||||
return "masteradministrator", nil, true, nil
|
||||
return MasterUser, true, true, nil
|
||||
}
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
|
@ -128,15 +104,15 @@ func VerifyUserToken(tokenString string) (username string, networks []string, is
|
|||
// check that user exists
|
||||
user, err = GetUser(claims.UserName)
|
||||
if err != nil {
|
||||
return "", nil, false, err
|
||||
return "", false, false, err
|
||||
}
|
||||
|
||||
if user.UserName != "" {
|
||||
return claims.UserName, claims.Networks, claims.IsAdmin, nil
|
||||
return claims.UserName, claims.IsSuperAdmin, claims.IsAdmin, nil
|
||||
}
|
||||
err = errors.New("user does not exist")
|
||||
}
|
||||
return "", nil, false, err
|
||||
return "", false, false, err
|
||||
}
|
||||
|
||||
// VerifyHostToken - [hosts] Only
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic/acls/nodeacls"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/validation"
|
||||
)
|
||||
|
@ -51,9 +50,6 @@ func DeleteNetwork(network string) error {
|
|||
nodeCount, err := GetNetworkNonServerNodeCount(network)
|
||||
if nodeCount == 0 || database.IsEmptyRecord(err) {
|
||||
// delete server nodes first then db records
|
||||
if err = pro.RemoveAllNetworkUsers(network); err != nil {
|
||||
logger.Log(0, "failed to remove network users on network delete for network", network, err.Error())
|
||||
}
|
||||
return database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
|
||||
}
|
||||
return errors.New("node check failed. All nodes must be deleted before deleting network")
|
||||
|
@ -81,22 +77,12 @@ func CreateNetwork(network models.Network) (models.Network, error) {
|
|||
network.SetNodesLastModified()
|
||||
network.SetNetworkLastModified()
|
||||
|
||||
pro.AddProNetDefaults(&network)
|
||||
|
||||
if len(network.ProSettings.AllowedGroups) == 0 {
|
||||
network.ProSettings.AllowedGroups = []string{pro.DEFAULT_ALLOWED_GROUPS}
|
||||
}
|
||||
|
||||
err := ValidateNetwork(&network, false)
|
||||
if err != nil {
|
||||
//logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return models.Network{}, err
|
||||
}
|
||||
|
||||
if err = pro.InitializeNetworkUsers(network.NetID); err != nil {
|
||||
return models.Network{}, err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(&network)
|
||||
if err != nil {
|
||||
return models.Network{}, err
|
||||
|
@ -106,11 +92,6 @@ func CreateNetwork(network models.Network) (models.Network, error) {
|
|||
return models.Network{}, err
|
||||
}
|
||||
|
||||
// == add all current users to network as network users ==
|
||||
if err = InitializeNetUsers(&network); err != nil {
|
||||
return network, err
|
||||
}
|
||||
|
||||
return network, nil
|
||||
}
|
||||
|
||||
|
@ -302,28 +283,24 @@ func IsNetworkNameUnique(network *models.Network) (bool, error) {
|
|||
}
|
||||
|
||||
// UpdateNetwork - updates a network with another network's fields
|
||||
func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, bool, []string, []string, error) {
|
||||
func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, bool, error) {
|
||||
if err := ValidateNetwork(newNetwork, true); err != nil {
|
||||
return false, false, false, nil, nil, err
|
||||
return false, false, false, err
|
||||
}
|
||||
if newNetwork.NetID == currentNetwork.NetID {
|
||||
hasrangeupdate4 := newNetwork.AddressRange != currentNetwork.AddressRange
|
||||
hasrangeupdate6 := newNetwork.AddressRange6 != currentNetwork.AddressRange6
|
||||
hasholepunchupdate := newNetwork.DefaultUDPHolePunch != currentNetwork.DefaultUDPHolePunch
|
||||
groupDelta := append(StringDifference(newNetwork.ProSettings.AllowedGroups, currentNetwork.ProSettings.AllowedGroups),
|
||||
StringDifference(currentNetwork.ProSettings.AllowedGroups, newNetwork.ProSettings.AllowedGroups)...)
|
||||
userDelta := append(StringDifference(newNetwork.ProSettings.AllowedUsers, currentNetwork.ProSettings.AllowedUsers),
|
||||
StringDifference(currentNetwork.ProSettings.AllowedUsers, newNetwork.ProSettings.AllowedUsers)...)
|
||||
data, err := json.Marshal(newNetwork)
|
||||
if err != nil {
|
||||
return false, false, false, nil, nil, err
|
||||
return false, false, false, err
|
||||
}
|
||||
newNetwork.SetNetworkLastModified()
|
||||
err = database.Insert(newNetwork.NetID, string(data), database.NETWORKS_TABLE_NAME)
|
||||
return hasrangeupdate4, hasrangeupdate6, hasholepunchupdate, groupDelta, userDelta, err
|
||||
return hasrangeupdate4, hasrangeupdate6, hasholepunchupdate, err
|
||||
}
|
||||
// copy values
|
||||
return false, false, false, nil, nil, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
|
||||
return false, false, false, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
|
||||
}
|
||||
|
||||
// GetNetwork - gets a network from database
|
||||
|
@ -375,15 +352,6 @@ func ValidateNetwork(network *models.Network, isUpdate bool) error {
|
|||
}
|
||||
}
|
||||
|
||||
if network.ProSettings != nil {
|
||||
if network.ProSettings.DefaultAccessLevel < pro.NET_ADMIN || network.ProSettings.DefaultAccessLevel > pro.NO_ACCESS {
|
||||
return fmt.Errorf("invalid access level")
|
||||
}
|
||||
if network.ProSettings.DefaultUserClientLimit < 0 || network.ProSettings.DefaultUserNodeLimit < 0 {
|
||||
return fmt.Errorf("invalid node/client limit provided")
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic/acls"
|
||||
"github.com/gravitl/netmaker/logic/acls/nodeacls"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/gravitl/netmaker/validation"
|
||||
|
@ -235,12 +234,6 @@ func deleteNodeByID(node *models.Node) error {
|
|||
if servercfg.IsDNSMode() {
|
||||
SetDNS()
|
||||
}
|
||||
if node.OwnerID != "" {
|
||||
err = pro.DissociateNetworkUserNode(node.OwnerID, node.Network, node.ID.String())
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to dissasociate", node.OwnerID, "from node", node.ID.String(), ":", err.Error())
|
||||
}
|
||||
}
|
||||
_, err = nodeacls.RemoveNodeACL(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()))
|
||||
if err != nil {
|
||||
// ignoring for now, could hit a nil pointer if delete called twice
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
package pro
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
)
|
||||
|
||||
// AddProNetDefaults - adds default values to a network model
|
||||
func AddProNetDefaults(network *models.Network) {
|
||||
if network.ProSettings == nil {
|
||||
newProSettings := promodels.ProNetwork{
|
||||
DefaultAccessLevel: NO_ACCESS,
|
||||
DefaultUserNodeLimit: 0,
|
||||
DefaultUserClientLimit: 0,
|
||||
AllowedUsers: []string{},
|
||||
AllowedGroups: []string{DEFAULT_ALLOWED_GROUPS},
|
||||
}
|
||||
network.ProSettings = &newProSettings
|
||||
}
|
||||
if network.ProSettings.AllowedUsers == nil {
|
||||
network.ProSettings.AllowedUsers = []string{}
|
||||
}
|
||||
if network.ProSettings.AllowedGroups == nil {
|
||||
network.ProSettings.AllowedGroups = []string{DEFAULT_ALLOWED_GROUPS}
|
||||
}
|
||||
}
|
||||
|
||||
// isUserGroupAllowed - checks if a user group is allowed on a network
|
||||
func isUserGroupAllowed(network *models.Network, groupName string) bool {
|
||||
if network.ProSettings != nil {
|
||||
if len(network.ProSettings.AllowedGroups) > 0 {
|
||||
for i := range network.ProSettings.AllowedGroups {
|
||||
currentGroup := network.ProSettings.AllowedGroups[i]
|
||||
if currentGroup == DEFAULT_ALLOWED_GROUPS || currentGroup == groupName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isUserInAllowedUsers(network *models.Network, userName string) bool {
|
||||
if network.ProSettings != nil {
|
||||
if len(network.ProSettings.AllowedUsers) > 0 {
|
||||
for i := range network.ProSettings.AllowedUsers {
|
||||
currentUser := network.ProSettings.AllowedUsers[i]
|
||||
if currentUser == DEFAULT_ALLOWED_USERS || currentUser == userName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsUserAllowed - checks if given username + groups if a user is allowed on network
|
||||
func IsUserAllowed(network *models.Network, userName string, groups []string) bool {
|
||||
isGroupAllowed := false
|
||||
for _, g := range groups {
|
||||
if isUserGroupAllowed(network, g) {
|
||||
isGroupAllowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return isUserInAllowedUsers(network, userName) || isGroupAllowed
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
package pro
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNetworkProSettings(t *testing.T) {
|
||||
t.Run("Uninitialized with pro", func(t *testing.T) {
|
||||
network := models.Network{
|
||||
NetID: "helloworld",
|
||||
}
|
||||
assert.Nil(t, network.ProSettings)
|
||||
})
|
||||
t.Run("Initialized with pro", func(t *testing.T) {
|
||||
network := models.Network{
|
||||
NetID: "helloworld",
|
||||
}
|
||||
AddProNetDefaults(&network)
|
||||
assert.NotNil(t, network.ProSettings)
|
||||
})
|
||||
t.Run("Net Zero Defaults set correctly with Pro", func(t *testing.T) {
|
||||
network := models.Network{
|
||||
NetID: "helloworld",
|
||||
}
|
||||
AddProNetDefaults(&network)
|
||||
assert.NotNil(t, network.ProSettings)
|
||||
assert.Equal(t, NO_ACCESS, network.ProSettings.DefaultAccessLevel)
|
||||
assert.Equal(t, 0, network.ProSettings.DefaultUserClientLimit)
|
||||
assert.Equal(t, 0, network.ProSettings.DefaultUserNodeLimit)
|
||||
})
|
||||
t.Run("Net Defaults set correctly with Pro", func(t *testing.T) {
|
||||
network := models.Network{
|
||||
NetID: "helloworld",
|
||||
ProSettings: &promodels.ProNetwork{
|
||||
DefaultAccessLevel: NET_ADMIN,
|
||||
DefaultUserNodeLimit: 10,
|
||||
DefaultUserClientLimit: 25,
|
||||
},
|
||||
}
|
||||
AddProNetDefaults(&network)
|
||||
assert.NotNil(t, network.ProSettings)
|
||||
assert.Equal(t, NET_ADMIN, network.ProSettings.DefaultAccessLevel)
|
||||
assert.Equal(t, 25, network.ProSettings.DefaultUserClientLimit)
|
||||
assert.Equal(t, 10, network.ProSettings.DefaultUserNodeLimit)
|
||||
})
|
||||
t.Run("Net Defaults set to allow all groups/users", func(t *testing.T) {
|
||||
network := models.Network{
|
||||
NetID: "helloworld",
|
||||
ProSettings: &promodels.ProNetwork{
|
||||
DefaultAccessLevel: NET_ADMIN,
|
||||
DefaultUserNodeLimit: 10,
|
||||
DefaultUserClientLimit: 25,
|
||||
},
|
||||
}
|
||||
AddProNetDefaults(&network)
|
||||
assert.NotNil(t, network.ProSettings)
|
||||
assert.Equal(t, len(network.ProSettings.AllowedGroups), 1)
|
||||
assert.Equal(t, len(network.ProSettings.AllowedUsers), 0)
|
||||
})
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
package pro
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
)
|
||||
|
||||
// InitializeNetworkUsers - intializes network users for a given network
|
||||
func InitializeNetworkUsers(network string) error {
|
||||
|
||||
_, err := database.FetchRecord(database.NETWORK_USER_TABLE_NAME, network)
|
||||
if err != nil && database.IsEmptyRecord(err) {
|
||||
newNetUserMap := make(promodels.NetworkUserMap)
|
||||
netUserData, err := json.Marshal(newNetUserMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return database.Insert(network, string(netUserData), database.NETWORK_USER_TABLE_NAME)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// GetNetworkUsers - gets the network users table
|
||||
func GetNetworkUsers(network string) (promodels.NetworkUserMap, error) {
|
||||
currentUsers, err := database.FetchRecord(database.NETWORK_USER_TABLE_NAME, network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var userMap promodels.NetworkUserMap
|
||||
if err = json.Unmarshal([]byte(currentUsers), &userMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userMap, nil
|
||||
}
|
||||
|
||||
// CreateNetworkUser - adds a network user to db
|
||||
func CreateNetworkUser(network *models.Network, user *promodels.NetworkUser) error {
|
||||
|
||||
if DoesNetworkUserExist(network.NetID, user.ID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
currentUsers, err := GetNetworkUsers(network.NetID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.SetDefaults()
|
||||
currentUsers.Add(user)
|
||||
data, err := json.Marshal(currentUsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return database.Insert(network.NetID, string(data), database.NETWORK_USER_TABLE_NAME)
|
||||
}
|
||||
|
||||
// DeleteNetworkUser - deletes a network user and removes from all networks
|
||||
func DeleteNetworkUser(network, userid string) error {
|
||||
currentUsers, err := GetNetworkUsers(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
currentUsers.Delete(promodels.NetworkUserID(userid))
|
||||
data, err := json.Marshal(currentUsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return database.Insert(network, string(data), database.NETWORK_USER_TABLE_NAME)
|
||||
}
|
||||
|
||||
// DissociateNetworkUserNode - removes a node from a given user's node list
|
||||
func DissociateNetworkUserNode(userid, networkid, nodeid string) error {
|
||||
nuser, err := GetNetworkUser(networkid, promodels.NetworkUserID(userid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, n := range nuser.Nodes {
|
||||
if n == nodeid {
|
||||
nuser.Nodes = removeStringIndex(nuser.Nodes, i)
|
||||
break
|
||||
}
|
||||
}
|
||||
return UpdateNetworkUser(networkid, nuser)
|
||||
}
|
||||
|
||||
// DissociateNetworkUserClient - removes a client from a given user's client list
|
||||
func DissociateNetworkUserClient(userid, networkid, clientid string) error {
|
||||
nuser, err := GetNetworkUser(networkid, promodels.NetworkUserID(userid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, n := range nuser.Clients {
|
||||
if n == clientid {
|
||||
nuser.Clients = removeStringIndex(nuser.Clients, i)
|
||||
break
|
||||
}
|
||||
}
|
||||
return UpdateNetworkUser(networkid, nuser)
|
||||
}
|
||||
|
||||
// AssociateNetworkUserClient - removes a client from a given user's client list
|
||||
func AssociateNetworkUserClient(userid, networkid, clientid string) error {
|
||||
nuser, err := GetNetworkUser(networkid, promodels.NetworkUserID(userid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var found bool
|
||||
for _, n := range nuser.Clients {
|
||||
if n == clientid {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
return nil
|
||||
} else {
|
||||
nuser.Clients = append(nuser.Clients, clientid)
|
||||
}
|
||||
|
||||
return UpdateNetworkUser(networkid, nuser)
|
||||
}
|
||||
|
||||
func removeStringIndex(s []string, index int) []string {
|
||||
ret := make([]string, 0)
|
||||
ret = append(ret, s[:index]...)
|
||||
return append(ret, s[index+1:]...)
|
||||
}
|
||||
|
||||
// GetNetworkUser - fetches a network user from a given network
|
||||
func GetNetworkUser(network string, userID promodels.NetworkUserID) (*promodels.NetworkUser, error) {
|
||||
currentUsers, err := GetNetworkUsers(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if currentUsers[userID].ID == "" {
|
||||
return nil, fmt.Errorf("user %s does not exist", userID)
|
||||
}
|
||||
currentNetUser := currentUsers[userID]
|
||||
return ¤tNetUser, nil
|
||||
}
|
||||
|
||||
// DoesNetworkUserExist - check if networkuser exists
|
||||
func DoesNetworkUserExist(network string, userID promodels.NetworkUserID) bool {
|
||||
_, err := GetNetworkUser(network, userID)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// UpdateNetworkUser - gets a network user from given network
|
||||
func UpdateNetworkUser(network string, newUser *promodels.NetworkUser) error {
|
||||
currentUsers, err := GetNetworkUsers(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
currentUsers[newUser.ID] = *newUser
|
||||
newUsersData, err := json.Marshal(¤tUsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return database.Insert(network, string(newUsersData), database.NETWORK_USER_TABLE_NAME)
|
||||
}
|
||||
|
||||
// RemoveAllNetworkUsers - removes all network users from given network
|
||||
func RemoveAllNetworkUsers(network string) error {
|
||||
return database.DeleteRecord(database.NETWORK_USER_TABLE_NAME, network)
|
||||
}
|
||||
|
||||
// IsUserNodeAllowed - given a list of nodes, determine if the user's node is allowed based on ID
|
||||
// Checks if node is in given nodes list as well as being in user's list
|
||||
func IsUserNodeAllowed(nodes []models.Node, network, userID, nodeID string) bool {
|
||||
|
||||
netUser, err := GetNetworkUser(network, promodels.NetworkUserID(userID))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range nodes {
|
||||
if nodes[i].ID.String() == nodeID {
|
||||
for j := range netUser.Nodes {
|
||||
if netUser.Nodes[j] == nodeID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsUserClientAllowed - given a list of clients, determine if the user's client is allowed based on ID
|
||||
// Checks if client is in given ext client list as well as being in user's list
|
||||
func IsUserClientAllowed(clients []models.ExtClient, network, userID, clientID string) bool {
|
||||
|
||||
netUser, err := GetNetworkUser(network, promodels.NetworkUserID(userID))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range clients {
|
||||
if clients[i].ClientID == clientID {
|
||||
for j := range netUser.Clients {
|
||||
if netUser.Clients[j] == clientID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsUserNetAdmin - checks if a user is a net admin or not
|
||||
func IsUserNetAdmin(network, userID string) bool {
|
||||
user, err := GetNetworkUser(network, promodels.NetworkUserID(userID))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return user.AccessLevel == NET_ADMIN
|
||||
}
|
||||
|
||||
// MakeNetAdmin - makes a given user a network admin on given network
|
||||
func MakeNetAdmin(network, userID string) (ok bool) {
|
||||
user, err := GetNetworkUser(network, promodels.NetworkUserID(userID))
|
||||
if err != nil {
|
||||
return ok
|
||||
}
|
||||
user.AccessLevel = NET_ADMIN
|
||||
if err = UpdateNetworkUser(network, user); err != nil {
|
||||
return ok
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AssignAccessLvl - gives a user a specified access level
|
||||
func AssignAccessLvl(network, userID string, accesslvl int) (ok bool) {
|
||||
user, err := GetNetworkUser(network, promodels.NetworkUserID(userID))
|
||||
if err != nil {
|
||||
return ok
|
||||
}
|
||||
user.AccessLevel = accesslvl
|
||||
if err = UpdateNetworkUser(network, user); err != nil {
|
||||
return ok
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
package pro
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
database.InitializeDatabase()
|
||||
defer database.CloseDB()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestNetworkUserLogic(t *testing.T) {
|
||||
networkUser := promodels.NetworkUser{
|
||||
ID: "helloworld",
|
||||
}
|
||||
network := models.Network{
|
||||
NetID: "skynet",
|
||||
AddressRange: "192.168.0.0/24",
|
||||
}
|
||||
tmpCNode := models.CommonNode{
|
||||
ID: uuid.New(),
|
||||
}
|
||||
tempNode := models.Node{}
|
||||
tempNode.CommonNode = tmpCNode
|
||||
nodes := []models.Node{
|
||||
tempNode,
|
||||
}
|
||||
|
||||
clients := []models.ExtClient{
|
||||
{
|
||||
ClientID: "coolclient",
|
||||
},
|
||||
}
|
||||
AddProNetDefaults(&network)
|
||||
t.Run("Net Users initialized successfully", func(t *testing.T) {
|
||||
err := InitializeNetworkUsers(network.NetID)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("Error when no network users", func(t *testing.T) {
|
||||
user, err := GetNetworkUser(network.NetID, networkUser.ID)
|
||||
assert.Nil(t, user)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
|
||||
t.Run("Successful net user create", func(t *testing.T) {
|
||||
DeleteNetworkUser(network.NetID, string(networkUser.ID))
|
||||
err := CreateNetworkUser(&network, &networkUser)
|
||||
assert.Nil(t, err)
|
||||
user, err := GetNetworkUser(network.NetID, networkUser.ID)
|
||||
assert.NotNil(t, user)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 0, user.AccessLevel)
|
||||
assert.Equal(t, 0, user.ClientLimit)
|
||||
})
|
||||
|
||||
t.Run("Successful net user update", func(t *testing.T) {
|
||||
networkUser.AccessLevel = 0
|
||||
networkUser.ClientLimit = 1
|
||||
err := UpdateNetworkUser(network.NetID, &networkUser)
|
||||
assert.Nil(t, err)
|
||||
user, err := GetNetworkUser(network.NetID, networkUser.ID)
|
||||
assert.NotNil(t, user)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 0, user.AccessLevel)
|
||||
assert.Equal(t, 1, user.ClientLimit)
|
||||
})
|
||||
|
||||
t.Run("Successful net user node isallowed", func(t *testing.T) {
|
||||
networkUser.Nodes = append(networkUser.Nodes, nodes[0].ID.String())
|
||||
err := UpdateNetworkUser(network.NetID, &networkUser)
|
||||
assert.Nil(t, err)
|
||||
isUserNodeAllowed := IsUserNodeAllowed(nodes[:], network.NetID, string(networkUser.ID), nodes[0].ID.String())
|
||||
assert.True(t, isUserNodeAllowed)
|
||||
})
|
||||
|
||||
t.Run("Successful net user node not allowed", func(t *testing.T) {
|
||||
isUserNodeAllowed := IsUserNodeAllowed(nodes[:], network.NetID, string(networkUser.ID), "notanode")
|
||||
assert.False(t, isUserNodeAllowed)
|
||||
})
|
||||
|
||||
t.Run("Successful net user client isallowed", func(t *testing.T) {
|
||||
networkUser.Clients = append(networkUser.Clients, "coolclient")
|
||||
err := UpdateNetworkUser(network.NetID, &networkUser)
|
||||
assert.Nil(t, err)
|
||||
isUserClientAllowed := IsUserClientAllowed(clients[:], network.NetID, string(networkUser.ID), "coolclient")
|
||||
assert.True(t, isUserClientAllowed)
|
||||
})
|
||||
|
||||
t.Run("Successful net user client not allowed", func(t *testing.T) {
|
||||
isUserClientAllowed := IsUserClientAllowed(clients[:], network.NetID, string(networkUser.ID), "notaclient")
|
||||
assert.False(t, isUserClientAllowed)
|
||||
})
|
||||
|
||||
t.Run("Successful net user delete", func(t *testing.T) {
|
||||
err := DeleteNetworkUser(network.NetID, string(networkUser.ID))
|
||||
assert.Nil(t, err)
|
||||
user, err := GetNetworkUser(network.NetID, networkUser.ID)
|
||||
assert.Nil(t, user)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package pro
|
||||
|
||||
const (
|
||||
// == NET ACCESS END == indicates access for system admin (control of netmaker)
|
||||
// NET_ADMIN - indicates access for network admin (control of network)
|
||||
NET_ADMIN = 0
|
||||
// NODE_ACCESS - indicates access for
|
||||
NODE_ACCESS = 1
|
||||
// CLIENT_ACCESS - indicates access for network user (limited to nodes + ext clients)
|
||||
CLIENT_ACCESS = 2
|
||||
// NO_ACCESS - indicates user has no access to network
|
||||
NO_ACCESS = 3
|
||||
// == NET ACCESS END ==
|
||||
// DEFAULT_ALLOWED_GROUPS - default user group for all networks
|
||||
DEFAULT_ALLOWED_GROUPS = "*"
|
||||
// DEFAULT_ALLOWED_USERS - default allowed users for a network
|
||||
DEFAULT_ALLOWED_USERS = "*"
|
||||
// DB_GROUPS_KEY - represents db groups
|
||||
DB_GROUPS_KEY = "netmaker-groups"
|
||||
)
|
|
@ -1,80 +0,0 @@
|
|||
package pro
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
)
|
||||
|
||||
// InitializeGroups - initialize groups data structure if not present in the DB
|
||||
func InitializeGroups() error {
|
||||
if !DoesUserGroupExist(DEFAULT_ALLOWED_GROUPS) {
|
||||
return InsertUserGroup(DEFAULT_ALLOWED_GROUPS)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertUserGroup - inserts a group into the
|
||||
func InsertUserGroup(groupName promodels.UserGroupName) error {
|
||||
currentGroups, err := GetUserGroups()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentGroups[groupName] = promodels.Void{}
|
||||
newData, err := json.Marshal(¤tGroups)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(DB_GROUPS_KEY, string(newData), database.USER_GROUPS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// DeleteUserGroup - deletes a group from database
|
||||
func DeleteUserGroup(groupName promodels.UserGroupName) error {
|
||||
var newGroups promodels.UserGroups
|
||||
currentGroupRecords, err := database.FetchRecord(database.USER_GROUPS_TABLE_NAME, DB_GROUPS_KEY)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(currentGroupRecords), &newGroups); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(newGroups, groupName)
|
||||
newData, err := json.Marshal(&newGroups)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert(DB_GROUPS_KEY, string(newData), database.USER_GROUPS_TABLE_NAME)
|
||||
}
|
||||
|
||||
// GetUserGroups - get groups of users
|
||||
func GetUserGroups() (promodels.UserGroups, error) {
|
||||
var returnGroups promodels.UserGroups
|
||||
groupsRecord, err := database.FetchRecord(database.USER_GROUPS_TABLE_NAME, DB_GROUPS_KEY)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return make(promodels.UserGroups, 1), nil
|
||||
}
|
||||
return returnGroups, err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal([]byte(groupsRecord), &returnGroups); err != nil {
|
||||
return returnGroups, err
|
||||
}
|
||||
|
||||
return returnGroups, nil
|
||||
}
|
||||
|
||||
// DoesUserGroupExist - checks if a user group exists
|
||||
func DoesUserGroupExist(group promodels.UserGroupName) bool {
|
||||
currentGroups, err := GetUserGroups()
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
for k := range currentGroups {
|
||||
if k == group {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package pro
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUserGroupLogic(t *testing.T) {
|
||||
|
||||
t.Run("User Groups initialized successfully", func(t *testing.T) {
|
||||
err := InitializeGroups()
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("Check for default group", func(t *testing.T) {
|
||||
groups, err := GetUserGroups()
|
||||
assert.Nil(t, err)
|
||||
var hasdefault bool
|
||||
for k := range groups {
|
||||
if string(k) == DEFAULT_ALLOWED_GROUPS {
|
||||
hasdefault = true
|
||||
}
|
||||
}
|
||||
assert.True(t, hasdefault)
|
||||
})
|
||||
|
||||
t.Run("User Groups created successfully", func(t *testing.T) {
|
||||
err := InsertUserGroup(promodels.UserGroupName("group1"))
|
||||
assert.Nil(t, err)
|
||||
err = InsertUserGroup(promodels.UserGroupName("group2"))
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("User Groups deleted successfully", func(t *testing.T) {
|
||||
err := DeleteUserGroup(promodels.UserGroupName("group1"))
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, DoesUserGroupExist(promodels.UserGroupName("group1")))
|
||||
})
|
||||
}
|
|
@ -1,23 +1,16 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
const (
|
||||
// ALL_NETWORK_ACCESS - represents all networks
|
||||
ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
|
||||
|
||||
master_uname = "masteradministrator"
|
||||
MasterUser = "masteradministrator"
|
||||
Forbidden_Msg = "forbidden"
|
||||
Forbidden_Err = models.Error(Forbidden_Msg)
|
||||
Unauthorized_Msg = "unauthorized"
|
||||
|
@ -28,152 +21,46 @@ const (
|
|||
func SecurityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var errorResponse = models.ErrorResponse{
|
||||
Code: http.StatusForbidden, Message: Forbidden_Msg,
|
||||
}
|
||||
r.Header.Set("ismaster", "no")
|
||||
|
||||
var params = mux.Vars(r)
|
||||
bearerToken := r.Header.Get("Authorization")
|
||||
// to have a custom DNS service adding entries
|
||||
// we should refactor this, but is for the special case of an external service to query the DNS api
|
||||
if strings.Contains(r.RequestURI, "/dns") && strings.ToUpper(r.Method) == "GET" && authenticateDNSToken(bearerToken) {
|
||||
// do dns stuff
|
||||
r.Header.Set("user", "nameserver")
|
||||
networks, _ := json.Marshal([]string{ALL_NETWORK_ACCESS})
|
||||
r.Header.Set("networks", string(networks))
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
var networkName = params["networkname"]
|
||||
if len(networkName) == 0 {
|
||||
networkName = params["network"]
|
||||
}
|
||||
networks, username, err := UserPermissions(reqAdmin, networkName, bearerToken)
|
||||
username, err := UserPermissions(reqAdmin, bearerToken)
|
||||
if err != nil {
|
||||
ReturnErrorResponse(w, r, errorResponse)
|
||||
ReturnErrorResponse(w, r, FormatError(err, err.Error()))
|
||||
return
|
||||
}
|
||||
// detect masteradmin
|
||||
if len(networks) > 0 && networks[0] == ALL_NETWORK_ACCESS {
|
||||
if username == MasterUser {
|
||||
r.Header.Set("ismaster", "yes")
|
||||
}
|
||||
networksJson, err := json.Marshal(&networks)
|
||||
if err != nil {
|
||||
ReturnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
r.Header.Set("user", username)
|
||||
r.Header.Set("networks", string(networksJson))
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// NetUserSecurityCheck - Check if network user has appropriate permissions
|
||||
func NetUserSecurityCheck(isNodes, isClients bool, next http.Handler) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var errorResponse = models.ErrorResponse{
|
||||
Code: http.StatusForbidden, Message: Forbidden_Msg,
|
||||
}
|
||||
r.Header.Set("ismaster", "no")
|
||||
|
||||
var params = mux.Vars(r)
|
||||
var netUserName = params["networkuser"]
|
||||
var network = params["network"]
|
||||
|
||||
bearerToken := r.Header.Get("Authorization")
|
||||
|
||||
var tokenSplit = strings.Split(bearerToken, " ")
|
||||
var authToken = ""
|
||||
|
||||
if len(tokenSplit) < 2 {
|
||||
ReturnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
} else {
|
||||
authToken = tokenSplit[1]
|
||||
}
|
||||
|
||||
isMasterAuthenticated := authenticateMaster(authToken)
|
||||
if isMasterAuthenticated {
|
||||
r.Header.Set("user", "master token user")
|
||||
r.Header.Set("ismaster", "yes")
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
userName, _, isadmin, err := VerifyUserToken(authToken)
|
||||
if err != nil {
|
||||
ReturnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
r.Header.Set("user", userName)
|
||||
|
||||
if isadmin {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if isNodes || isClients {
|
||||
necessaryAccess := pro.NET_ADMIN
|
||||
if isClients {
|
||||
necessaryAccess = pro.CLIENT_ACCESS
|
||||
}
|
||||
if isNodes {
|
||||
necessaryAccess = pro.NODE_ACCESS
|
||||
}
|
||||
u, err := pro.GetNetworkUser(network, promodels.NetworkUserID(userName))
|
||||
if err != nil {
|
||||
ReturnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
if u.AccessLevel > necessaryAccess {
|
||||
ReturnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
} else if netUserName != userName {
|
||||
ReturnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// UserPermissions - checks token stuff
|
||||
func UserPermissions(reqAdmin bool, netname string, token string) ([]string, string, error) {
|
||||
func UserPermissions(reqAdmin bool, token string) (string, error) {
|
||||
var tokenSplit = strings.Split(token, " ")
|
||||
var authToken = ""
|
||||
userNetworks := []string{}
|
||||
|
||||
if len(tokenSplit) < 2 {
|
||||
return userNetworks, "", Unauthorized_Err
|
||||
return "", Unauthorized_Err
|
||||
} else {
|
||||
authToken = tokenSplit[1]
|
||||
}
|
||||
//all endpoints here require master so not as complicated
|
||||
if authenticateMaster(authToken) {
|
||||
// TODO log in as an actual admin user
|
||||
return []string{ALL_NETWORK_ACCESS}, master_uname, nil
|
||||
return MasterUser, nil
|
||||
}
|
||||
username, networks, isadmin, err := VerifyUserToken(authToken)
|
||||
username, issuperadmin, isadmin, err := VerifyUserToken(authToken)
|
||||
if err != nil {
|
||||
return nil, username, Unauthorized_Err
|
||||
return username, Unauthorized_Err
|
||||
}
|
||||
if !isadmin && reqAdmin {
|
||||
return nil, username, Forbidden_Err
|
||||
if reqAdmin && !(issuperadmin || isadmin) {
|
||||
return username, Forbidden_Err
|
||||
}
|
||||
userNetworks = networks
|
||||
if isadmin {
|
||||
return []string{ALL_NETWORK_ACCESS}, username, nil
|
||||
}
|
||||
// check network admin access
|
||||
if len(netname) > 0 && (len(userNetworks) == 0 || !authenticateNetworkUser(netname, userNetworks)) {
|
||||
return nil, username, Forbidden_Err
|
||||
}
|
||||
if servercfg.IsPro && len(netname) > 0 && !pro.IsUserNetAdmin(netname, username) {
|
||||
return nil, "", Forbidden_Err
|
||||
}
|
||||
return userNetworks, username, nil
|
||||
|
||||
return username, nil
|
||||
}
|
||||
|
||||
// Consider a more secure way of setting master key
|
||||
|
@ -181,23 +68,6 @@ func authenticateMaster(tokenString string) bool {
|
|||
return tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != ""
|
||||
}
|
||||
|
||||
func authenticateNetworkUser(network string, userNetworks []string) bool {
|
||||
networkexists, err := NetworkExists(network)
|
||||
if (err != nil && !database.IsEmptyRecord(err)) || !networkexists {
|
||||
return false
|
||||
}
|
||||
return StringSliceContains(userNetworks, network)
|
||||
}
|
||||
|
||||
// Consider a more secure way of setting master key
|
||||
func authenticateDNSToken(tokenString string) bool {
|
||||
tokens := strings.Split(tokenString, " ")
|
||||
if len(tokens) < 2 {
|
||||
return false
|
||||
}
|
||||
return len(servercfg.GetDNSKey()) > 0 && tokens[1] == servercfg.GetDNSKey()
|
||||
}
|
||||
|
||||
func ContinueIfUserMatch(next http.Handler) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var errorResponse = models.ErrorResponse{
|
||||
|
|
|
@ -2,13 +2,11 @@ package logic
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
)
|
||||
|
||||
// GetUser - gets a user
|
||||
|
@ -43,64 +41,17 @@ func GetReturnUser(username string) (models.ReturnUser, error) {
|
|||
// ToReturnUser - gets a user as a return user
|
||||
func ToReturnUser(user models.User) models.ReturnUser {
|
||||
return models.ReturnUser{
|
||||
UserName: user.UserName,
|
||||
Networks: user.Networks,
|
||||
IsAdmin: user.IsAdmin,
|
||||
Groups: user.Groups,
|
||||
UserName: user.UserName,
|
||||
IsSuperAdmin: user.IsSuperAdmin,
|
||||
IsAdmin: user.IsAdmin,
|
||||
RemoteGwIDs: user.RemoteGwIDs,
|
||||
}
|
||||
}
|
||||
|
||||
// GetGroupUsers - gets users in a group
|
||||
func GetGroupUsers(group string) ([]models.ReturnUser, error) {
|
||||
var returnUsers []models.ReturnUser
|
||||
users, err := GetUsers()
|
||||
if err != nil {
|
||||
return returnUsers, err
|
||||
}
|
||||
for _, user := range users {
|
||||
if StringSliceContains(user.Groups, group) {
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
return users, err
|
||||
}
|
||||
|
||||
// == PRO ==
|
||||
|
||||
// InitializeNetUsers - intializes network users for all users/networks
|
||||
func InitializeNetUsers(network *models.Network) error {
|
||||
// == add all current users to network as network users ==
|
||||
currentUsers, err := GetUsers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range currentUsers { // add all users to given network
|
||||
newUser := promodels.NetworkUser{
|
||||
ID: promodels.NetworkUserID(currentUsers[i].UserName),
|
||||
Clients: []string{},
|
||||
Nodes: []string{},
|
||||
AccessLevel: pro.NO_ACCESS,
|
||||
ClientLimit: 0,
|
||||
NodeLimit: 0,
|
||||
}
|
||||
if pro.IsUserAllowed(network, currentUsers[i].UserName, currentUsers[i].Groups) {
|
||||
newUser.AccessLevel = network.ProSettings.DefaultAccessLevel
|
||||
newUser.ClientLimit = network.ProSettings.DefaultUserClientLimit
|
||||
newUser.NodeLimit = network.ProSettings.DefaultUserNodeLimit
|
||||
}
|
||||
|
||||
if err = pro.CreateNetworkUser(network, &newUser); err != nil {
|
||||
logger.Log(0, "failed to add network user settings to user", string(newUser.ID), "on network", network.NetID)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetUserDefaults - sets the defaults of a user to avoid empty fields
|
||||
func SetUserDefaults(user *models.User) {
|
||||
if user.Groups == nil {
|
||||
user.Groups = []string{pro.DEFAULT_ALLOWED_GROUPS}
|
||||
if user.RemoteGwIDs == nil {
|
||||
user.RemoteGwIDs = make(map[string]struct{})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,3 +61,17 @@ func SortUsers(unsortedUsers []models.ReturnUser) {
|
|||
return unsortedUsers[i].UserName < unsortedUsers[j].UserName
|
||||
})
|
||||
}
|
||||
|
||||
// GetSuperAdmin - fetches superadmin user
|
||||
func GetSuperAdmin() (models.ReturnUser, error) {
|
||||
users, err := GetUsers()
|
||||
if err != nil {
|
||||
return models.ReturnUser{}, err
|
||||
}
|
||||
for _, user := range users {
|
||||
if user.IsSuperAdmin {
|
||||
return user, nil
|
||||
}
|
||||
}
|
||||
return models.ReturnUser{}, errors.New("superadmin not found")
|
||||
}
|
||||
|
|
5
main.go
5
main.go
|
@ -19,7 +19,6 @@ import (
|
|||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"github.com/gravitl/netmaker/migrate"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/mq"
|
||||
|
@ -83,10 +82,6 @@ func initialize() { // Client Mode Prereq Check
|
|||
|
||||
logic.SetJWTSecret()
|
||||
|
||||
if err = pro.InitializeGroups(); err != nil {
|
||||
logger.Log(0, "could not initialize default user group, \"*\"")
|
||||
}
|
||||
|
||||
err = logic.TimerCheckpoint()
|
||||
if err != nil {
|
||||
logger.Log(1, "Timer error occurred: ", err.Error())
|
||||
|
|
|
@ -5,12 +5,51 @@ import (
|
|||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
// Run - runs all migrations
|
||||
func Run() {
|
||||
updateEnrollmentKeys()
|
||||
assignSuperAdmin()
|
||||
}
|
||||
|
||||
func assignSuperAdmin() {
|
||||
users, err := logic.GetUsers()
|
||||
if err != nil || len(users) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ok, _ := logic.HasSuperAdmin(); ok {
|
||||
return
|
||||
}
|
||||
createdSuperAdmin := false
|
||||
for _, u := range users {
|
||||
if u.IsAdmin {
|
||||
user, err := logic.GetUser(u.UserName)
|
||||
if err != nil {
|
||||
slog.Error("error getting user", "user", u.UserName, "error", err.Error())
|
||||
continue
|
||||
}
|
||||
user.IsSuperAdmin = true
|
||||
user.IsAdmin = false
|
||||
err = logic.UpsertUser(*user)
|
||||
if err != nil {
|
||||
slog.Error("error updating user to superadmin", "user", user.UserName, "error", err.Error())
|
||||
continue
|
||||
} else {
|
||||
createdSuperAdmin = true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !createdSuperAdmin {
|
||||
slog.Error("failed to create superadmin!!")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func updateEnrollmentKeys() {
|
||||
|
|
|
@ -16,14 +16,16 @@ 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"`
|
||||
}
|
||||
|
||||
// CustomExtClient - struct for CustomExtClient params
|
||||
type CustomExtClient struct {
|
||||
ClientID string `json:"clientid,omitempty"`
|
||||
PublicKey string `json:"publickey,omitempty"`
|
||||
DNS string `json:"dns,omitempty"`
|
||||
ExtraAllowedIPs []string `json:"extraallowedips,omitempty"`
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
DeniedACLs map[string]struct{} `json:"deniednodeacls" bson:"acls,omitempty"`
|
||||
ClientID string `json:"clientid,omitempty"`
|
||||
PublicKey string `json:"publickey,omitempty"`
|
||||
DNS string `json:"dns,omitempty"`
|
||||
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"`
|
||||
}
|
||||
|
|
|
@ -2,30 +2,27 @@ package models
|
|||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
)
|
||||
|
||||
// Network Struct - contains info for a given unique network
|
||||
// At some point, need to replace all instances of Name with something else like Identifier
|
||||
type Network struct {
|
||||
AddressRange string `json:"addressrange" bson:"addressrange" validate:"omitempty,cidrv4"`
|
||||
AddressRange6 string `json:"addressrange6" bson:"addressrange6" validate:"omitempty,cidrv6"`
|
||||
NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=32,netid_valid"`
|
||||
NodesLastModified int64 `json:"nodeslastmodified" bson:"nodeslastmodified"`
|
||||
NetworkLastModified int64 `json:"networklastmodified" bson:"networklastmodified"`
|
||||
DefaultInterface string `json:"defaultinterface" bson:"defaultinterface" validate:"min=1,max=35"`
|
||||
DefaultListenPort int32 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
|
||||
NodeLimit int32 `json:"nodelimit" bson:"nodelimit"`
|
||||
DefaultPostDown string `json:"defaultpostdown" bson:"defaultpostdown"`
|
||||
DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
|
||||
AllowManualSignUp string `json:"allowmanualsignup" bson:"allowmanualsignup" validate:"checkyesorno"`
|
||||
IsIPv4 string `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
|
||||
IsIPv6 string `json:"isipv6" bson:"isipv6" validate:"checkyesorno"`
|
||||
DefaultUDPHolePunch string `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
|
||||
DefaultMTU int32 `json:"defaultmtu" bson:"defaultmtu"`
|
||||
DefaultACL string `json:"defaultacl" bson:"defaultacl" yaml:"defaultacl" validate:"checkyesorno"`
|
||||
ProSettings *promodels.ProNetwork `json:"prosettings,omitempty" bson:"prosettings,omitempty" yaml:"prosettings,omitempty"`
|
||||
AddressRange string `json:"addressrange" bson:"addressrange" validate:"omitempty,cidrv4"`
|
||||
AddressRange6 string `json:"addressrange6" bson:"addressrange6" validate:"omitempty,cidrv6"`
|
||||
NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=32,netid_valid"`
|
||||
NodesLastModified int64 `json:"nodeslastmodified" bson:"nodeslastmodified"`
|
||||
NetworkLastModified int64 `json:"networklastmodified" bson:"networklastmodified"`
|
||||
DefaultInterface string `json:"defaultinterface" bson:"defaultinterface" validate:"min=1,max=35"`
|
||||
DefaultListenPort int32 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
|
||||
NodeLimit int32 `json:"nodelimit" bson:"nodelimit"`
|
||||
DefaultPostDown string `json:"defaultpostdown" bson:"defaultpostdown"`
|
||||
DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
|
||||
AllowManualSignUp string `json:"allowmanualsignup" bson:"allowmanualsignup" validate:"checkyesorno"`
|
||||
IsIPv4 string `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
|
||||
IsIPv6 string `json:"isipv6" bson:"isipv6" validate:"checkyesorno"`
|
||||
DefaultUDPHolePunch string `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
|
||||
DefaultMTU int32 `json:"defaultmtu" bson:"defaultmtu"`
|
||||
DefaultACL string `json:"defaultacl" bson:"defaultacl" yaml:"defaultacl" validate:"checkyesorno"`
|
||||
}
|
||||
|
||||
// SaveData - sensitive fields of a network that should be kept the same
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package promodels
|
||||
|
||||
// NetworkUserID - ID field for a network user
|
||||
type NetworkUserID string
|
||||
|
||||
// NetworkUser - holds fields for a network user
|
||||
type NetworkUser struct {
|
||||
AccessLevel int `json:"accesslevel" bson:"accesslevel" yaml:"accesslevel"`
|
||||
ClientLimit int `json:"clientlimit" bson:"clientlimit" yaml:"clientlimit"`
|
||||
NodeLimit int `json:"nodelimit" bson:"nodelimit" yaml:"nodelimit"`
|
||||
ID NetworkUserID `json:"id" bson:"id" yaml:"id"`
|
||||
Clients []string `json:"clients" bson:"clients" yaml:"clients"`
|
||||
Nodes []string `json:"nodes" bson:"nodes" yaml:"nodes"`
|
||||
}
|
||||
|
||||
// NetworkUserMap - map of network users
|
||||
type NetworkUserMap map[NetworkUserID]NetworkUser
|
||||
|
||||
// NetworkUserMap.Delete - deletes a network user struct from a given map in memory
|
||||
func (N NetworkUserMap) Delete(ID NetworkUserID) {
|
||||
delete(N, ID)
|
||||
}
|
||||
|
||||
// NetworkUserMap.Add - adds a network user struct to given network user map in memory
|
||||
func (N NetworkUserMap) Add(User *NetworkUser) {
|
||||
N[User.ID] = *User
|
||||
}
|
||||
|
||||
// SetDefaults - adds the defaults to network user
|
||||
func (U *NetworkUser) SetDefaults() {
|
||||
if U.Clients == nil {
|
||||
U.Clients = []string{}
|
||||
}
|
||||
if U.Nodes == nil {
|
||||
U.Nodes = []string{}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package promodels
|
||||
|
||||
// ProNetwork - struct for all pro Network related fields
|
||||
type ProNetwork struct {
|
||||
DefaultAccessLevel int `json:"defaultaccesslevel" bson:"defaultaccesslevel" yaml:"defaultaccesslevel"`
|
||||
DefaultUserNodeLimit int `json:"defaultusernodelimit" bson:"defaultusernodelimit" yaml:"defaultusernodelimit"`
|
||||
DefaultUserClientLimit int `json:"defaultuserclientlimit" bson:"defaultuserclientlimit" yaml:"defaultuserclientlimit"`
|
||||
AllowedUsers []string `json:"allowedusers" bson:"allowedusers" yaml:"allowedusers"`
|
||||
AllowedGroups []string `json:"allowedgroups" bson:"allowedgroups" yaml:"allowedgroups"`
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package promodels
|
||||
|
||||
type Void struct{}
|
||||
|
||||
// UserGroupName - string representing a group name
|
||||
type UserGroupName string
|
||||
|
||||
// UserGroups - groups type, holds group names
|
||||
type UserGroups map[UserGroupName]Void
|
|
@ -24,19 +24,19 @@ type AuthParams struct {
|
|||
|
||||
// User struct - struct for Users
|
||||
type User struct {
|
||||
UserName string `json:"username" bson:"username" validate:"min=3,max=40,in_charset|email"`
|
||||
Password string `json:"password" bson:"password" validate:"required,min=5"`
|
||||
Networks []string `json:"networks" bson:"networks"`
|
||||
IsAdmin bool `json:"isadmin" bson:"isadmin"`
|
||||
Groups []string `json:"groups" bson:"groups" yaml:"groups"`
|
||||
UserName string `json:"username" bson:"username" validate:"min=3,max=40,in_charset|email"`
|
||||
Password string `json:"password" bson:"password" validate:"required,min=5"`
|
||||
IsAdmin bool `json:"isadmin" bson:"isadmin"`
|
||||
IsSuperAdmin bool `json:"issuperadmin"`
|
||||
RemoteGwIDs map[string]struct{} `json:"remote_gw_ids"`
|
||||
}
|
||||
|
||||
// ReturnUser - return user struct
|
||||
type ReturnUser struct {
|
||||
UserName string `json:"username" bson:"username"`
|
||||
Networks []string `json:"networks" bson:"networks"`
|
||||
IsAdmin bool `json:"isadmin" bson:"isadmin"`
|
||||
Groups []string `json:"groups" bson:"groups"`
|
||||
UserName string `json:"username"`
|
||||
IsAdmin bool `json:"isadmin"`
|
||||
IsSuperAdmin bool `json:"issuperadmin"`
|
||||
RemoteGwIDs map[string]struct{} `json:"remote_gw_ids"`
|
||||
}
|
||||
|
||||
// UserAuthParams - user auth params struct
|
||||
|
@ -47,13 +47,33 @@ type UserAuthParams struct {
|
|||
|
||||
// UserClaims - user claims struct
|
||||
type UserClaims struct {
|
||||
IsAdmin bool
|
||||
UserName string
|
||||
Networks []string
|
||||
Groups []string
|
||||
IsAdmin bool
|
||||
IsSuperAdmin bool
|
||||
UserName string
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// IngressGwUsers - struct to hold users on a ingress gw
|
||||
type IngressGwUsers struct {
|
||||
NodeID string `json:"node_id"`
|
||||
Network string `json:"network"`
|
||||
Users []ReturnUser `json:"users"`
|
||||
}
|
||||
|
||||
// UserRemoteGws - struct to hold user's remote gws
|
||||
type UserRemoteGws struct {
|
||||
GwID string `json:"remote_access_gw_id"`
|
||||
GWName string `json:"gw_name"`
|
||||
Network string `json:"network"`
|
||||
Connected bool `json:"connected"`
|
||||
GwClient ExtClient `json:"gw_client"`
|
||||
}
|
||||
|
||||
// UserRemoteGwsReq - struct to hold user remote acccess gws req
|
||||
type UserRemoteGwsReq struct {
|
||||
RemoteAccessClientID string `json:"remote_access_clientid"`
|
||||
}
|
||||
|
||||
// SuccessfulUserLoginResponse - successlogin struct
|
||||
type SuccessfulUserLoginResponse struct {
|
||||
UserName string
|
||||
|
|
|
@ -1,365 +0,0 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"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", logic.SecurityCheck(true, http.HandlerFunc(getAllNetworkUsers))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/networkusers/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkUsers))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/networkusers/{network}/{networkuser}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkUser))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/networkusers/{network}", logic.SecurityCheck(true, http.HandlerFunc(createNetworkUser))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/networkusers/{network}", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkUser))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/networkusers/data/{networkuser}/me", logic.NetUserSecurityCheck(false, false, http.HandlerFunc(getNetworkUserData))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/networkusers/{network}/{networkuser}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetworkUser))).Methods(http.MethodDelete)
|
||||
}
|
||||
|
||||
// == 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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
if networkUserName == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("netuserToGet"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
u, err := logic.GetUser(networkUserName)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.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,
|
||||
}
|
||||
newData.User.SetDefaults()
|
||||
// check network level permissions
|
||||
if doesNetworkAllow := pro.IsUserAllowed(&networks[i], networkUserName, u.Groups); doesNetworkAllow || netUser.AccessLevel == pro.NET_ADMIN {
|
||||
netNodes, err := logic.GetNetworkNodes(netID)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) && netUser.AccessLevel == pro.NET_ADMIN {
|
||||
newData.Networks = append(newData.Networks, networks[i])
|
||||
} else {
|
||||
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.String()) {
|
||||
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 {
|
||||
newData.Vpn = append(newData.Vpn, netNodes[i])
|
||||
if clients, err := logic.GetExtClientsByID(netNodes[i].ID.String(), 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 {
|
||||
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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
var allNetUsers = make(allNetworkUsers, len(networks))
|
||||
|
||||
for i := range networks {
|
||||
netusers, err := pro.GetNetworkUsers(networks[i].NetID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
netusers, err := pro.GetNetworkUsers(netname)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
netuserToGet := params["networkuser"]
|
||||
if netuserToGet == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("netuserToGet"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
netuser, err := pro.GetNetworkUser(netname, promodels.NetworkUserID(netuserToGet))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
var networkuser promodels.NetworkUser
|
||||
|
||||
// we decode our body request params
|
||||
err = json.NewDecoder(r.Body).Decode(&networkuser)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
err = pro.CreateNetworkUser(&network, &networkuser)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
var networkuser promodels.NetworkUser
|
||||
|
||||
// we decode our body request params
|
||||
err = json.NewDecoder(r.Body).Decode(&networkuser)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if networkuser.ID == "" || !pro.DoesNetworkUserExist(netname, networkuser.ID) {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid user "+string(networkuser.ID)), "badrequest"))
|
||||
return
|
||||
}
|
||||
if networkuser.AccessLevel < pro.NET_ADMIN || networkuser.AccessLevel > pro.NO_ACCESS {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid user access level provided"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
if networkuser.ClientLimit < 0 || networkuser.NodeLimit < 0 {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("negative user limit provided"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
u, err := logic.GetUser(string(networkuser.ID))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid user "+string(networkuser.ID)), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
if !pro.IsUserAllowed(&network, u.UserName, u.Groups) {
|
||||
logic.ReturnErrorResponse(w, r, logic.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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.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 {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
netuserToDelete := params["networkuser"]
|
||||
if netuserToDelete == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("no group name provided"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := pro.DeleteNetworkUser(netname, netuserToDelete); err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
)
|
||||
|
||||
func UserGroupsHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/usergroups", logic.SecurityCheck(true, http.HandlerFunc(getUserGroups))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/usergroups/{usergroup}", logic.SecurityCheck(true, http.HandlerFunc(createUserGroup))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/usergroups/{usergroup}", logic.SecurityCheck(true, http.HandlerFunc(deleteUserGroup))).Methods(http.MethodDelete)
|
||||
}
|
||||
|
||||
func getUserGroups(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
logger.Log(1, r.Header.Get("user"), "requested fetching user groups")
|
||||
|
||||
userGroups, err := pro.GetUserGroups()
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
// Returns all the groups in JSON format
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(userGroups)
|
||||
}
|
||||
|
||||
func createUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
newGroup := params["usergroup"]
|
||||
|
||||
logger.Log(1, r.Header.Get("user"), "requested creating user group", newGroup)
|
||||
|
||||
if newGroup == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("no group name provided"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
err := pro.InsertUserGroup(promodels.UserGroupName(newGroup))
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func deleteUserGroup(w http.ResponseWriter, r *http.Request) {
|
||||
var params = mux.Vars(r)
|
||||
groupToDelete := params["usergroup"]
|
||||
logger.Log(1, r.Header.Get("user"), "requested deleting user group", groupToDelete)
|
||||
|
||||
if groupToDelete == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("no group name provided"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := pro.DeleteUserGroup(promodels.UserGroupName(groupToDelete)); err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
268
pro/controllers/users.go
Normal file
268
pro/controllers/users.go
Normal file
|
@ -0,0 +1,268 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
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/ingress/{ingress_id}", logic.SecurityCheck(true, http.HandlerFunc(ingressGatewayUsers))).Methods(http.MethodGet)
|
||||
}
|
||||
|
||||
// swagger:route POST /api/users/{username}/remote_access_gw user attachUserToRemoteAccessGateway
|
||||
//
|
||||
// Attach User to a remote access gateway.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
var params = mux.Vars(r)
|
||||
username := params["username"]
|
||||
remoteGwID := params["remote_access_gateway_id"]
|
||||
if username == "" || remoteGwID == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params `username` and `remote_access_gateway_id`"), "badrequest"))
|
||||
return
|
||||
}
|
||||
user, err := logic.GetUser(username)
|
||||
if err != nil {
|
||||
slog.Error("failed to fetch user: ", "username", username, "error", err.Error())
|
||||
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("superadmins/admins have access to all gateways"), "badrequest"))
|
||||
return
|
||||
}
|
||||
node, err := logic.GetNodeByID(remoteGwID)
|
||||
if err != nil {
|
||||
slog.Error("failed to fetch gateway node", "nodeID", remoteGwID, "error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch remote access gateway node, error: %v", err), "badrequest"))
|
||||
return
|
||||
}
|
||||
if !node.IsIngressGateway {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("node is not a remote access gateway"), "badrequest"))
|
||||
return
|
||||
}
|
||||
if user.RemoteGwIDs == nil {
|
||||
user.RemoteGwIDs = make(map[string]struct{})
|
||||
}
|
||||
user.RemoteGwIDs[node.ID.String()] = struct{}{}
|
||||
err = logic.UpsertUser(*user)
|
||||
if err != nil {
|
||||
slog.Error("failed to update user's gateways", "user", username, "error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch remote access gateway node,error: %v", err), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/users/{username}/remote_access_gw user removeUserFromRemoteAccessGW
|
||||
//
|
||||
// Attach User to a remote access gateway.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: userBodyResponse
|
||||
func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
var params = mux.Vars(r)
|
||||
username := params["username"]
|
||||
remoteGwID := params["remote_access_gateway_id"]
|
||||
if username == "" || remoteGwID == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params `username` and `remote_access_gateway_id`"), "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
|
||||
}
|
||||
delete(user.RemoteGwIDs, remoteGwID)
|
||||
go func(user models.User, remoteGwID string) {
|
||||
extclients, err := logic.GetAllExtClients()
|
||||
if err != nil {
|
||||
slog.Error("failed to fetch extclients", "error", err)
|
||||
return
|
||||
}
|
||||
for _, extclient := range extclients {
|
||||
if extclient.OwnerID == user.UserName && remoteGwID == extclient.IngressGatewayID {
|
||||
logic.DeleteExtClient(extclient.Network, extclient.ClientID)
|
||||
}
|
||||
}
|
||||
}(*user, remoteGwID)
|
||||
|
||||
err = logic.UpsertUser(*user)
|
||||
if err != nil {
|
||||
slog.Error("failed to update user gateways", "user", username, "error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to fetch remote access gaetway node "+err.Error()), "badrequest"))
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
|
||||
}
|
||||
|
||||
// swagger:route GET "/api/users/{username}/remote_access_gw" nodes getUserRemoteAccessGws
|
||||
//
|
||||
// Get an individual node.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: nodeResponse
|
||||
func getUserRemoteAccessGws(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
|
||||
}
|
||||
var req models.UserRemoteGwsReq
|
||||
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
|
||||
}
|
||||
if req.RemoteAccessClientID == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("remote access client id cannot be empty"), "badrequest"))
|
||||
return
|
||||
}
|
||||
userGws := make(map[string][]models.UserRemoteGws)
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
for _, extClient := range allextClients {
|
||||
if extClient.RemoteAccessClientID == req.RemoteAccessClientID && extClient.OwnerID == username {
|
||||
node, err := logic.GetNodeByID(extClient.IngressGatewayID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if node.PendingDelete {
|
||||
continue
|
||||
}
|
||||
host, err := logic.GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := user.RemoteGwIDs[node.ID.String()]; ok {
|
||||
gws := userGws[node.Network]
|
||||
|
||||
gws = append(gws, models.UserRemoteGws{
|
||||
GwID: node.ID.String(),
|
||||
GWName: host.Name,
|
||||
Network: node.Network,
|
||||
GwClient: extClient,
|
||||
Connected: true,
|
||||
})
|
||||
userGws[node.Network] = gws
|
||||
delete(user.RemoteGwIDs, node.ID.String())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// add remaining gw nodes to resp
|
||||
for gwID := range user.RemoteGwIDs {
|
||||
node, err := logic.GetNodeByID(gwID)
|
||||
if err != nil {
|
||||
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,
|
||||
})
|
||||
userGws[node.Network] = gws
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(userGws)
|
||||
}
|
||||
|
||||
// swagger:route GET /api/nodes/{network}/{nodeid}/ingress/users users 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)
|
||||
ingressID := params["ingress_id"]
|
||||
node, err := logic.GetNodeByID(ingressID)
|
||||
if err != nil {
|
||||
slog.Error("failed to get ingress node", "error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
gwUsers, err := logic.GetIngressGwUsers(node)
|
||||
if err != nil {
|
||||
slog.Error("failed to get users on ingress gateway", "nodeid", ingressID, "network", node.Network, "user", r.Header.Get("user"),
|
||||
"error", err)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(gwUsers)
|
||||
}
|
|
@ -25,9 +25,8 @@ func InitPro() {
|
|||
controller.HttpHandlers = append(
|
||||
controller.HttpHandlers,
|
||||
proControllers.MetricHandlers,
|
||||
proControllers.NetworkUsersHandlers,
|
||||
proControllers.UserGroupsHandlers,
|
||||
proControllers.RelayHandlers,
|
||||
proControllers.UserHandlers,
|
||||
)
|
||||
logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() {
|
||||
// == License Handling ==
|
||||
|
|
|
@ -320,17 +320,6 @@ func GetMasterKey() string {
|
|||
return key
|
||||
}
|
||||
|
||||
// GetDNSKey - gets the configured dns key of server
|
||||
func GetDNSKey() string {
|
||||
key := ""
|
||||
if os.Getenv("DNS_KEY") != "" {
|
||||
key = os.Getenv("DNS_KEY")
|
||||
} else if config.Config.Server.DNSKey != "" {
|
||||
key = config.Config.Server.DNSKey
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
// GetAllowedOrigin - get the allowed origin
|
||||
func GetAllowedOrigin() string {
|
||||
allowedorigin := "*"
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/logic/acls"
|
||||
"github.com/gravitl/netmaker/logic/acls/nodeacls"
|
||||
"github.com/gravitl/netmaker/logic/pro"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -59,10 +59,6 @@ func setNetworkDefaults() error {
|
|||
return err
|
||||
}
|
||||
for _, network := range networks {
|
||||
if err = pro.InitializeNetworkUsers(network.NetID); err != nil {
|
||||
logger.Log(0, "could not initialize NetworkUsers on network", network.NetID)
|
||||
}
|
||||
pro.AddProNetDefaults(&network)
|
||||
update := false
|
||||
newNet := network
|
||||
if strings.Contains(network.NetID, ".") {
|
||||
|
@ -85,7 +81,7 @@ func setNetworkDefaults() error {
|
|||
}
|
||||
} else {
|
||||
network.SetDefaults()
|
||||
_, _, _, _, _, err = logic.UpdateNetwork(&network, &network)
|
||||
_, _, _, err = logic.UpdateNetwork(&network, &network)
|
||||
if err != nil {
|
||||
logger.Log(0, "could not set defaults on network", network.NetID)
|
||||
}
|
||||
|
@ -102,13 +98,12 @@ func setUserDefaults() error {
|
|||
for _, user := range users {
|
||||
updateUser, err := logic.GetUser(user.UserName)
|
||||
if err != nil {
|
||||
logger.Log(0, "could not update user", updateUser.UserName)
|
||||
slog.Error("could not get user", "user", updateUser.UserName, "error", err.Error())
|
||||
}
|
||||
logic.SetUserDefaults(updateUser)
|
||||
copyUser := updateUser
|
||||
copyUser.Password = ""
|
||||
if _, err = logic.UpdateUser(copyUser, updateUser); err != nil {
|
||||
logger.Log(0, "could not update user", updateUser.UserName)
|
||||
err = logic.UpsertUser(*updateUser)
|
||||
if err != nil {
|
||||
slog.Error("could not update user", "user", updateUser.UserName, "error", err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
Loading…
Reference in a new issue