mirror of
				https://github.com/gravitl/netmaker.git
				synced 2025-11-04 20:11:11 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			304 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			304 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package controller
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"errors"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/google/uuid"
 | 
						|
	"github.com/gorilla/mux"
 | 
						|
	"github.com/gravitl/netmaker/logger"
 | 
						|
	"github.com/gravitl/netmaker/logic"
 | 
						|
	"github.com/gravitl/netmaker/models"
 | 
						|
	"github.com/gravitl/netmaker/mq"
 | 
						|
)
 | 
						|
 | 
						|
func aclHandlers(r *mux.Router) {
 | 
						|
	r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(getAcls))).
 | 
						|
		Methods(http.MethodGet)
 | 
						|
	r.HandleFunc("/api/v1/acls/policy_types", logic.SecurityCheck(true, http.HandlerFunc(aclPolicyTypes))).
 | 
						|
		Methods(http.MethodGet)
 | 
						|
	r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(createAcl))).
 | 
						|
		Methods(http.MethodPost)
 | 
						|
	r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(updateAcl))).
 | 
						|
		Methods(http.MethodPut)
 | 
						|
	r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(deleteAcl))).
 | 
						|
		Methods(http.MethodDelete)
 | 
						|
	r.HandleFunc("/api/v1/acls/debug", logic.SecurityCheck(true, http.HandlerFunc(aclDebug))).
 | 
						|
		Methods(http.MethodGet)
 | 
						|
}
 | 
						|
 | 
						|
// @Summary     List Acl Policy types
 | 
						|
// @Router      /api/v1/acls/policy_types [get]
 | 
						|
// @Tags        ACL
 | 
						|
// @Accept      json
 | 
						|
// @Success     200 {array} models.SuccessResponse
 | 
						|
// @Failure     500 {object} models.ErrorResponse
 | 
						|
func aclPolicyTypes(w http.ResponseWriter, r *http.Request) {
 | 
						|
	resp := models.AclPolicyTypes{
 | 
						|
		RuleTypes: []models.AclPolicyType{
 | 
						|
			models.DevicePolicy,
 | 
						|
			models.UserPolicy,
 | 
						|
		},
 | 
						|
		SrcGroupTypes: []models.AclGroupType{
 | 
						|
			models.UserAclID,
 | 
						|
			models.UserGroupAclID,
 | 
						|
			models.DeviceAclID,
 | 
						|
		},
 | 
						|
		DstGroupTypes: []models.AclGroupType{
 | 
						|
			models.DeviceAclID,
 | 
						|
			// models.NetmakerIPAclID,
 | 
						|
			// models.NetmakerSubNetRangeAClID,
 | 
						|
		},
 | 
						|
		ProtocolTypes: []models.ProtocolType{
 | 
						|
			{
 | 
						|
				Name: models.Any,
 | 
						|
				AllowedProtocols: []models.Protocol{
 | 
						|
					models.ALL,
 | 
						|
				},
 | 
						|
				PortRange:        "All ports",
 | 
						|
				AllowPortSetting: false,
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Name: models.Http,
 | 
						|
				AllowedProtocols: []models.Protocol{
 | 
						|
					models.TCP,
 | 
						|
				},
 | 
						|
				PortRange: "80",
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Name: models.Https,
 | 
						|
				AllowedProtocols: []models.Protocol{
 | 
						|
					models.TCP,
 | 
						|
				},
 | 
						|
				PortRange: "443",
 | 
						|
			},
 | 
						|
			// {
 | 
						|
			// 	Name: "MySQL",
 | 
						|
			// 	AllowedProtocols: []models.Protocol{
 | 
						|
			// 		models.TCP,
 | 
						|
			// 	},
 | 
						|
			// 	PortRange: "3306",
 | 
						|
			// },
 | 
						|
			// {
 | 
						|
			// 	Name: "DNS TCP",
 | 
						|
			// 	AllowedProtocols: []models.Protocol{
 | 
						|
			// 		models.TCP,
 | 
						|
			// 	},
 | 
						|
			// 	PortRange: "53",
 | 
						|
			// },
 | 
						|
			// {
 | 
						|
			// 	Name: "DNS UDP",
 | 
						|
			// 	AllowedProtocols: []models.Protocol{
 | 
						|
			// 		models.UDP,
 | 
						|
			// 	},
 | 
						|
			// 	PortRange: "53",
 | 
						|
			// },
 | 
						|
			{
 | 
						|
				Name: models.AllTCP,
 | 
						|
				AllowedProtocols: []models.Protocol{
 | 
						|
					models.TCP,
 | 
						|
				},
 | 
						|
				PortRange: "All ports",
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Name: models.AllUDP,
 | 
						|
				AllowedProtocols: []models.Protocol{
 | 
						|
					models.UDP,
 | 
						|
				},
 | 
						|
				PortRange: "All ports",
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Name: models.ICMPService,
 | 
						|
				AllowedProtocols: []models.Protocol{
 | 
						|
					models.ICMP,
 | 
						|
				},
 | 
						|
				PortRange: "",
 | 
						|
			},
 | 
						|
			{
 | 
						|
				Name: models.Custom,
 | 
						|
				AllowedProtocols: []models.Protocol{
 | 
						|
					models.UDP,
 | 
						|
					models.TCP,
 | 
						|
				},
 | 
						|
				PortRange:        "All ports",
 | 
						|
				AllowPortSetting: true,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	logic.ReturnSuccessResponseWithJson(w, r, resp, "fetched acls types")
 | 
						|
}
 | 
						|
 | 
						|
func aclDebug(w http.ResponseWriter, r *http.Request) {
 | 
						|
	nodeID, _ := url.QueryUnescape(r.URL.Query().Get("node"))
 | 
						|
	peerID, _ := url.QueryUnescape(r.URL.Query().Get("peer"))
 | 
						|
	node, err := logic.GetNodeByID(nodeID)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	peer, err := logic.GetNodeByID(peerID)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	allowed, _ := logic.IsNodeAllowedToCommunicate(node, peer, true)
 | 
						|
	logic.ReturnSuccessResponseWithJson(w, r, allowed, "fetched all acls in the network ")
 | 
						|
}
 | 
						|
 | 
						|
// @Summary     List Acls in a network
 | 
						|
// @Router      /api/v1/acls [get]
 | 
						|
// @Tags        ACL
 | 
						|
// @Accept      json
 | 
						|
// @Success     200 {array} models.SuccessResponse
 | 
						|
// @Failure     500 {object} models.ErrorResponse
 | 
						|
func getAcls(w http.ResponseWriter, r *http.Request) {
 | 
						|
	netID := r.URL.Query().Get("network")
 | 
						|
	if netID == "" {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network id param is missing"), "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	// check if network exists
 | 
						|
	_, err := logic.GetNetwork(netID)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	acls, err := logic.ListAclsByNetwork(models.NetworkID(netID))
 | 
						|
	if err != nil {
 | 
						|
		logger.Log(0, r.Header.Get("user"), "failed to get all network acl entries: ", err.Error())
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	logic.SortAclEntrys(acls[:])
 | 
						|
	logic.ReturnSuccessResponseWithJson(w, r, acls, "fetched all acls in the network "+netID)
 | 
						|
}
 | 
						|
 | 
						|
// @Summary     Create Acl
 | 
						|
// @Router      /api/v1/acls [post]
 | 
						|
// @Tags        ACL
 | 
						|
// @Accept      json
 | 
						|
// @Success     200 {array} models.SuccessResponse
 | 
						|
// @Failure     500 {object} models.ErrorResponse
 | 
						|
func createAcl(w http.ResponseWriter, r *http.Request) {
 | 
						|
	var req models.Acl
 | 
						|
	err := json.NewDecoder(r.Body).Decode(&req)
 | 
						|
	if err != nil {
 | 
						|
		logger.Log(0, "error decoding request body: ",
 | 
						|
			err.Error())
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	user, err := logic.GetUser(r.Header.Get("user"))
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	err = logic.ValidateCreateAclReq(req)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	acl := req
 | 
						|
	acl.ID = uuid.New().String()
 | 
						|
	acl.CreatedBy = user.UserName
 | 
						|
	acl.CreatedAt = time.Now().UTC()
 | 
						|
	acl.Default = false
 | 
						|
	if acl.ServiceType == models.Any {
 | 
						|
		acl.Port = []string{}
 | 
						|
		acl.Proto = models.ALL
 | 
						|
	}
 | 
						|
	// validate create acl policy
 | 
						|
	if !logic.IsAclPolicyValid(acl) {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	err = logic.InsertAcl(acl)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	acl, err = logic.GetAcl(acl.ID)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	go mq.PublishPeerUpdate(true)
 | 
						|
	logic.ReturnSuccessResponseWithJson(w, r, acl, "created acl successfully")
 | 
						|
}
 | 
						|
 | 
						|
// @Summary     Update Acl
 | 
						|
// @Router      /api/v1/acls [put]
 | 
						|
// @Tags        ACL
 | 
						|
// @Accept      json
 | 
						|
// @Success     200 {array} models.SuccessResponse
 | 
						|
// @Failure     500 {object} models.ErrorResponse
 | 
						|
func updateAcl(w http.ResponseWriter, r *http.Request) {
 | 
						|
	var updateAcl models.UpdateAclRequest
 | 
						|
	err := json.NewDecoder(r.Body).Decode(&updateAcl)
 | 
						|
	if err != nil {
 | 
						|
		logger.Log(0, "error decoding request body: ",
 | 
						|
			err.Error())
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	acl, err := logic.GetAcl(updateAcl.ID)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if !logic.IsAclPolicyValid(updateAcl.Acl) {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if updateAcl.Acl.NetworkID != acl.NetworkID {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy, network id mismatch"), "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if !acl.Default && updateAcl.NewName != "" {
 | 
						|
		//check if policy exists with same name
 | 
						|
		updateAcl.Acl.Name = updateAcl.NewName
 | 
						|
	}
 | 
						|
	err = logic.UpdateAcl(updateAcl.Acl, acl)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	go mq.PublishPeerUpdate(true)
 | 
						|
	logic.ReturnSuccessResponse(w, r, "updated acl "+acl.Name)
 | 
						|
}
 | 
						|
 | 
						|
// @Summary     Delete Acl
 | 
						|
// @Router      /api/v1/acls [delete]
 | 
						|
// @Tags        ACL
 | 
						|
// @Accept      json
 | 
						|
// @Success     200 {array} models.SuccessResponse
 | 
						|
// @Failure     500 {object} models.ErrorResponse
 | 
						|
func deleteAcl(w http.ResponseWriter, r *http.Request) {
 | 
						|
	aclID, _ := url.QueryUnescape(r.URL.Query().Get("acl_id"))
 | 
						|
	if aclID == "" {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("acl id is required"), "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	acl, err := logic.GetAcl(aclID)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if acl.Default {
 | 
						|
		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot delete default policy"), "badrequest"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	err = logic.DeleteAcl(acl)
 | 
						|
	if err != nil {
 | 
						|
		logic.ReturnErrorResponse(w, r,
 | 
						|
			logic.FormatError(errors.New("cannot delete default policy"), "internal"))
 | 
						|
		return
 | 
						|
	}
 | 
						|
	go mq.PublishPeerUpdate(true)
 | 
						|
	logic.ReturnSuccessResponse(w, r, "deleted acl "+acl.Name)
 | 
						|
}
 |