mirror of
https://github.com/gravitl/netmaker.git
synced 2024-11-15 14:20:25 +08:00
206 lines
5.7 KiB
Go
206 lines
5.7 KiB
Go
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"
|
|
Unauthorized_Msg = "unauthorized"
|
|
Unauthorized_Err = models.Error(Unauthorized_Msg)
|
|
)
|
|
|
|
// SecurityCheck - Check if user has appropriate permissions
|
|
func SecurityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
var errorResponse = models.ErrorResponse{
|
|
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")
|
|
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)
|
|
if err != nil {
|
|
ReturnErrorResponse(w, r, errorResponse)
|
|
return
|
|
}
|
|
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.StatusUnauthorized, Message: "unauthorized",
|
|
}
|
|
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) {
|
|
var tokenSplit = strings.Split(token, " ")
|
|
var authToken = ""
|
|
userNetworks := []string{}
|
|
|
|
if len(tokenSplit) < 2 {
|
|
return userNetworks, "", Unauthorized_Err
|
|
} else {
|
|
authToken = tokenSplit[1]
|
|
}
|
|
//all endpoints here require master so not as complicated
|
|
if authenticateMaster(authToken) {
|
|
return []string{ALL_NETWORK_ACCESS}, master_uname, nil
|
|
}
|
|
username, networks, isadmin, err := 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 && (len(userNetworks) == 0 || !authenticateNetworkUser(netname, userNetworks)) {
|
|
return nil, username, Unauthorized_Err
|
|
}
|
|
if isEE && len(netname) > 0 && !pro.IsUserNetAdmin(netname, username) {
|
|
return nil, "", Unauthorized_Err
|
|
}
|
|
return userNetworks, username, nil
|
|
}
|
|
|
|
// Consider a more secure way of setting master key
|
|
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{
|
|
Code: http.StatusUnauthorized, Message: Unauthorized_Msg,
|
|
}
|
|
var params = mux.Vars(r)
|
|
var requestedUser = params["username"]
|
|
if requestedUser != r.Header.Get("user") {
|
|
ReturnErrorResponse(w, r, errorResponse)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
}
|
|
}
|