adding security fixes

This commit is contained in:
afeiszli
2022-08-31 11:38:29 -04:00
parent e49dcc0796
commit 8fc9dac969
5 changed files with 69 additions and 61 deletions

View File

@@ -181,7 +181,7 @@ func nodeauth(next http.Handler) http.HandlerFunc {
func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc { func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var errorResponse = models.ErrorResponse{ var errorResponse = models.ErrorResponse{
Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", Code: http.StatusUnauthorized, Message: unauthorized_msg,
} }
var params = mux.Vars(r) var params = mux.Vars(r)
@@ -190,9 +190,6 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
//check that the request is for a valid network //check that the request is for a valid network
//if (networkCheck && !networkexists) || err != nil { //if (networkCheck && !networkexists) || err != nil {
if networkCheck && !networkexists { if networkCheck && !networkexists {
errorResponse = models.ErrorResponse{
Code: http.StatusNotFound, Message: "W1R3: This network does not exist. ",
}
returnErrorResponse(w, r, errorResponse) returnErrorResponse(w, r, errorResponse)
return return
} else { } else {
@@ -210,9 +207,6 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
if len(tokenSplit) > 1 { if len(tokenSplit) > 1 {
authToken = tokenSplit[1] authToken = tokenSplit[1]
} else { } else {
errorResponse = models.ErrorResponse{
Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.",
}
returnErrorResponse(w, r, errorResponse) returnErrorResponse(w, r, errorResponse)
return return
} }
@@ -229,9 +223,6 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
var nodeID = "" var nodeID = ""
username, networks, isadmin, errN := logic.VerifyUserToken(authToken) username, networks, isadmin, errN := logic.VerifyUserToken(authToken)
if errN != nil { if errN != nil {
errorResponse = models.ErrorResponse{
Code: http.StatusUnauthorized, Message: "W1R3: Unauthorized, Invalid Token Processed.",
}
returnErrorResponse(w, r, errorResponse) returnErrorResponse(w, r, errorResponse)
return return
} }
@@ -264,9 +255,6 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
} else { } else {
node, err := logic.GetNodeByID(nodeID) node, err := logic.GetNodeByID(nodeID)
if err != nil { if err != nil {
errorResponse = models.ErrorResponse{
Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.",
}
returnErrorResponse(w, r, errorResponse) returnErrorResponse(w, r, errorResponse)
return return
} }
@@ -285,9 +273,6 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
} }
} }
if !isAuthorized { if !isAuthorized {
errorResponse = models.ErrorResponse{
Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
}
returnErrorResponse(w, r, errorResponse) returnErrorResponse(w, r, errorResponse)
return return
} else { } else {

View File

@@ -2,7 +2,6 @@ package controller
import ( import (
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"strings" "strings"
@@ -14,14 +13,30 @@ import (
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
) )
const (
master_uname = "masteradministrator"
unauthorized_msg = "unauthorized"
unauthorized_err = models.Error(unauthorized_msg)
)
func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc { func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
/*
1. Check master token
2. Check if admin
3. Check if network admin
*/
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var errorResponse = models.ErrorResponse{ var errorResponse = models.ErrorResponse{
Code: http.StatusUnauthorized, Message: "W1R3: It's not you it's me.", Code: http.StatusUnauthorized, Message: unauthorized_msg,
} }
var params = mux.Vars(r) var params = mux.Vars(r)
bearerToken := r.Header.Get("Authorization") 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) { if strings.Contains(r.RequestURI, "/dns") && strings.ToUpper(r.Method) == "GET" && authenticateDNSToken(bearerToken) {
// do dns stuff // do dns stuff
r.Header.Set("user", "nameserver") r.Header.Set("user", "nameserver")
@@ -30,19 +45,17 @@ func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
return return
} }
var networkName = params["networkname"]
networks, username, err := SecurityCheck(reqAdmin, params["networkname"], bearerToken) if len(networkName) == 0 {
if err != nil { networkName = params["network"]
if strings.Contains(err.Error(), "does not exist") {
errorResponse.Code = http.StatusNotFound
} }
errorResponse.Message = err.Error() networks, username, err := SecurityCheck(reqAdmin, networkName, bearerToken)
if err != nil {
returnErrorResponse(w, r, errorResponse) returnErrorResponse(w, r, errorResponse)
return return
} }
networksJson, err := json.Marshal(&networks) networksJson, err := json.Marshal(&networks)
if err != nil { if err != nil {
errorResponse.Message = err.Error()
returnErrorResponse(w, r, errorResponse) returnErrorResponse(w, r, errorResponse)
return return
} }
@@ -54,46 +67,33 @@ func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
// SecurityCheck - checks token stuff // SecurityCheck - checks token stuff
func SecurityCheck(reqAdmin bool, netname string, token string) ([]string, string, error) { func SecurityCheck(reqAdmin bool, netname string, token string) ([]string, string, error) {
var hasBearer = true
var tokenSplit = strings.Split(token, " ") var tokenSplit = strings.Split(token, " ")
var authToken = "" var authToken = ""
userNetworks := []string{}
if len(tokenSplit) < 2 { if len(tokenSplit) < 2 {
hasBearer = false return userNetworks, "", unauthorized_err
} else { } else {
authToken = tokenSplit[1] authToken = tokenSplit[1]
} }
userNetworks := []string{}
//all endpoints here require master so not as complicated //all endpoints here require master so not as complicated
isMasterAuthenticated := authenticateMaster(authToken) if authenticateMaster(authToken) {
username := "" return []string{ALL_NETWORK_ACCESS}, master_uname, nil
if !hasBearer || !isMasterAuthenticated { }
userName, networks, isadmin, err := logic.VerifyUserToken(authToken) username, networks, isadmin, err := logic.VerifyUserToken(authToken)
username = userName
if err != nil { if err != nil {
return nil, username, errors.New("error verifying user token") return nil, username, unauthorized_err
} }
if !isadmin && reqAdmin { if !isadmin && reqAdmin {
return nil, username, errors.New("you are unauthorized to access this endpoint") return nil, username, unauthorized_err
} }
userNetworks = networks userNetworks = networks
if isadmin { if isadmin {
userNetworks = []string{ALL_NETWORK_ACCESS} return []string{ALL_NETWORK_ACCESS}, username, nil
} else {
networkexists, err := functions.NetworkExists(netname)
if err != nil && !database.IsEmptyRecord(err) {
return nil, "", err
} }
if netname != "" && !networkexists { // check network admin access
return nil, "", errors.New("this network does not exist") if len(netname) > 0 && (!authenticateNetworkUser(netname, userNetworks) || len(userNetworks) == 0) {
} return nil, username, unauthorized_err
}
} else if isMasterAuthenticated {
userNetworks = []string{ALL_NETWORK_ACCESS}
}
if len(userNetworks) == 0 {
userNetworks = append(userNetworks, NO_NETWORKS_PRESENT)
} }
return userNetworks, username, nil return userNetworks, username, nil
} }
@@ -103,6 +103,14 @@ func authenticateMaster(tokenString string) bool {
return tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != "" return tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != ""
} }
func authenticateNetworkUser(network string, userNetworks []string) bool {
networkexists, err := functions.NetworkExists(network)
if (err != nil && !database.IsEmptyRecord(err)) || !networkexists {
return false
}
return logic.StringSliceContains(userNetworks, network)
}
//Consider a more secure way of setting master key //Consider a more secure way of setting master key
func authenticateDNSToken(tokenString string) bool { func authenticateDNSToken(tokenString string) bool {
tokens := strings.Split(tokenString, " ") tokens := strings.Split(tokenString, " ")
@@ -115,7 +123,7 @@ func authenticateDNSToken(tokenString string) bool {
func continueIfUserMatch(next http.Handler) http.HandlerFunc { func continueIfUserMatch(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var errorResponse = models.ErrorResponse{ var errorResponse = models.ErrorResponse{
Code: http.StatusUnauthorized, Message: "W1R3: This doesn't look like you.", Code: http.StatusUnauthorized, Message: unauthorized_msg,
} }
var params = mux.Vars(r) var params = mux.Vars(r)
var requestedUser = params["username"] var requestedUser = params["username"]

View File

@@ -86,9 +86,9 @@ func initialize() { // Client Mode Prereq Check
logger.Log(0, "no OAuth provider found or not configured, continuing without OAuth") logger.Log(0, "no OAuth provider found or not configured, continuing without OAuth")
} }
err = serverctl.SetDefaultACLS() err = serverctl.SetDefaults()
if err != nil { if err != nil {
logger.FatalLog("error setting default acls: ", err.Error()) logger.FatalLog("error setting defaults: ", err.Error())
} }
if servercfg.IsClientMode() != "off" { if servercfg.IsClientMode() != "off" {

5
models/error.go Normal file
View File

@@ -0,0 +1,5 @@
package models
type Error string
func (e Error) Error() string { return string(e) }

View File

@@ -81,14 +81,24 @@ func SyncServerNetwork(network string) error {
return nil return nil
} }
// SetDefaultACLS - runs through each network to see if ACL's are set. If not, goes through each node in network and adds the default ACL func SetDefaults() error {
func SetDefaultACLS() error { if err := setNodeDefaults(); err != nil {
return err
}
return nil
}
// setNodeDefaults - runs through each node and set defaults
func setNodeDefaults() error {
// upgraded systems will not have ACL's set, which is why we need this function // upgraded systems will not have ACL's set, which is why we need this function
nodes, err := logic.GetAllNodes() nodes, err := logic.GetAllNodes()
if err != nil { if err != nil {
return err return err
} }
for i := range nodes { for i := range nodes {
logic.SetNodeDefaults(&nodes[i])
logic.UpdateNode(&nodes[i], &nodes[i])
currentNodeACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(nodes[i].Network), nodeacls.NodeID(nodes[i].ID)) currentNodeACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(nodes[i].Network), nodeacls.NodeID(nodes[i].ID))
if (err != nil && (database.IsEmptyRecord(err) || strings.Contains(err.Error(), "no node ACL present"))) || currentNodeACL == nil { if (err != nil && (database.IsEmptyRecord(err) || strings.Contains(err.Error(), "no node ACL present"))) || currentNodeACL == nil {
if _, err = nodeacls.CreateNodeACL(nodeacls.NetworkID(nodes[i].Network), nodeacls.NodeID(nodes[i].ID), acls.Allowed); err != nil { if _, err = nodeacls.CreateNodeACL(nodeacls.NetworkID(nodes[i].Network), nodeacls.NodeID(nodes[i].ID), acls.Allowed); err != nil {