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

View file

@ -2,7 +2,6 @@ package controller
import (
"encoding/json"
"errors"
"net/http"
"strings"
@ -14,14 +13,30 @@ import (
"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 {
/*
1. Check master token
2. Check if admin
3. Check if network admin
*/
return func(w http.ResponseWriter, r *http.Request) {
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)
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")
@ -30,19 +45,17 @@ func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
next.ServeHTTP(w, r)
return
}
networks, username, err := SecurityCheck(reqAdmin, params["networkname"], bearerToken)
var networkName = params["networkname"]
if len(networkName) == 0 {
networkName = params["network"]
}
networks, username, err := SecurityCheck(reqAdmin, networkName, bearerToken)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
errorResponse.Code = http.StatusNotFound
}
errorResponse.Message = err.Error()
returnErrorResponse(w, r, errorResponse)
return
}
networksJson, err := json.Marshal(&networks)
if err != nil {
errorResponse.Message = err.Error()
returnErrorResponse(w, r, errorResponse)
return
}
@ -54,46 +67,33 @@ func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
// SecurityCheck - checks token stuff
func SecurityCheck(reqAdmin bool, netname string, token string) ([]string, string, error) {
var hasBearer = true
var tokenSplit = strings.Split(token, " ")
var authToken = ""
userNetworks := []string{}
if len(tokenSplit) < 2 {
hasBearer = false
return userNetworks, "", unauthorized_err
} else {
authToken = tokenSplit[1]
}
userNetworks := []string{}
//all endpoints here require master so not as complicated
isMasterAuthenticated := authenticateMaster(authToken)
username := ""
if !hasBearer || !isMasterAuthenticated {
userName, networks, isadmin, err := logic.VerifyUserToken(authToken)
username = userName
if err != nil {
return nil, username, errors.New("error verifying user token")
}
if !isadmin && reqAdmin {
return nil, username, errors.New("you are unauthorized to access this endpoint")
}
userNetworks = networks
if isadmin {
userNetworks = []string{ALL_NETWORK_ACCESS}
} else {
networkexists, err := functions.NetworkExists(netname)
if err != nil && !database.IsEmptyRecord(err) {
return nil, "", err
}
if netname != "" && !networkexists {
return nil, "", errors.New("this network does not exist")
}
}
} else if isMasterAuthenticated {
userNetworks = []string{ALL_NETWORK_ACCESS}
if authenticateMaster(authToken) {
return []string{ALL_NETWORK_ACCESS}, master_uname, nil
}
if len(userNetworks) == 0 {
userNetworks = append(userNetworks, NO_NETWORKS_PRESENT)
username, networks, isadmin, err := logic.VerifyUserToken(authToken)
if err != nil {
return nil, username, unauthorized_err
}
if !isadmin && reqAdmin {
return nil, username, unauthorized_err
}
userNetworks = networks
if isadmin {
return []string{ALL_NETWORK_ACCESS}, username, nil
}
// check network admin access
if len(netname) > 0 && (!authenticateNetworkUser(netname, userNetworks) || len(userNetworks) == 0) {
return nil, username, unauthorized_err
}
return userNetworks, username, nil
}
@ -103,6 +103,14 @@ func authenticateMaster(tokenString string) bool {
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
func authenticateDNSToken(tokenString string) bool {
tokens := strings.Split(tokenString, " ")
@ -115,7 +123,7 @@ func authenticateDNSToken(tokenString string) bool {
func continueIfUserMatch(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
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 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")
}
err = serverctl.SetDefaultACLS()
err = serverctl.SetDefaults()
if err != nil {
logger.FatalLog("error setting default acls: ", err.Error())
logger.FatalLog("error setting defaults: ", err.Error())
}
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
}
// 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 SetDefaultACLS() error {
func SetDefaults() 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
nodes, err := logic.GetAllNodes()
if err != nil {
return err
}
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))
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 {