mirror of
https://github.com/gravitl/netmaker.git
synced 2025-09-06 05:04:27 +08:00
NET-1604: New Simplified RAC Apis (#3147)
* ipv6 fix for mobile apps
* simplified RAC APIs
* add response to invite api
* fix get config api
* fix middleware for auth
* add separate controller for rac apis
* Revert "ipv6 fix for mobile apps"
This reverts commit dc84d90be2
.
This commit is contained in:
parent
19c6a2f20f
commit
1f9808ff59
7 changed files with 270 additions and 1 deletions
|
@ -27,6 +27,7 @@ func userMiddleWare(handler http.Handler) http.Handler {
|
|||
r.Header.Set("TARGET_RSRC", "")
|
||||
r.Header.Set("RSRC_TYPE", "")
|
||||
r.Header.Set("TARGET_RSRC_ID", "")
|
||||
r.Header.Set("RAC", "")
|
||||
r.Header.Set("NET_ID", params["network"])
|
||||
if strings.Contains(route, "hosts") || strings.Contains(route, "nodes") {
|
||||
r.Header.Set("TARGET_RSRC", models.HostRsrc.String())
|
||||
|
@ -34,6 +35,9 @@ func userMiddleWare(handler http.Handler) http.Handler {
|
|||
if strings.Contains(route, "dns") {
|
||||
r.Header.Set("TARGET_RSRC", models.DnsRsrc.String())
|
||||
}
|
||||
if strings.Contains(route, "rac") {
|
||||
r.Header.Set("RAC", "true")
|
||||
}
|
||||
if strings.Contains(route, "users") {
|
||||
r.Header.Set("TARGET_RSRC", models.UserRsrc.String())
|
||||
}
|
||||
|
|
|
@ -45,6 +45,16 @@ type UserRemoteGws struct {
|
|||
NetworkAddresses []string `json:"network_addresses"`
|
||||
}
|
||||
|
||||
// UserRAGs - struct for user access gws
|
||||
type UserRAGs struct {
|
||||
GwID string `json:"remote_access_gw_id"`
|
||||
GWName string `json:"gw_name"`
|
||||
Network string `json:"network"`
|
||||
Connected bool `json:"connected"`
|
||||
IsInternetGateway bool `json:"is_internet_gateway"`
|
||||
Metadata string `json:"metadata"`
|
||||
}
|
||||
|
||||
// UserRemoteGwsReq - struct to hold user remote acccess gws req
|
||||
type UserRemoteGwsReq struct {
|
||||
RemoteAccessClientID string `json:"remote_access_clientid"`
|
||||
|
|
14
pro/controllers/rac.go
Normal file
14
pro/controllers/rac.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
)
|
||||
|
||||
func RacHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/v1/rac/networks", logic.SecurityCheck(false, http.HandlerFunc(getUserRemoteAccessNetworks))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/rac/network/{network}/access_points", logic.SecurityCheck(false, http.HandlerFunc(getUserRemoteAccessNetworkGateways))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/v1/rac/access_point/{access_point_id}/config", logic.SecurityCheck(false, http.HandlerFunc(getRemoteAccessGatewayConf))).Methods(http.MethodGet)
|
||||
}
|
|
@ -263,7 +263,6 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) {
|
|||
}(invite)
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, "triggered user invites")
|
||||
|
||||
}
|
||||
|
||||
// swagger:route GET /api/v1/users/invites user listUserInvites
|
||||
|
@ -816,6 +815,218 @@ func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
|
||||
}
|
||||
|
||||
// @Summary Get Users Remote Access Gw Networks.
|
||||
// @Router /api/users/{username}/remote_access_gw [get]
|
||||
// @Tags Users
|
||||
// @Param username path string true "Username to fetch all the gateways with access"
|
||||
// @Success 200 {object} map[string][]models.UserRemoteGws
|
||||
// @Failure 500 {object} models.ErrorResponse
|
||||
func getUserRemoteAccessNetworks(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
username := r.Header.Get("user")
|
||||
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
|
||||
}
|
||||
userGws := make(map[string][]models.UserRemoteGws)
|
||||
networks := []models.Network{}
|
||||
networkMap := make(map[string]struct{})
|
||||
userGwNodes := proLogic.GetUserRAGNodes(*user)
|
||||
for _, node := range userGwNodes {
|
||||
network, err := logic.GetNetwork(node.Network)
|
||||
if err != nil {
|
||||
slog.Error("failed to get node network", "error", err)
|
||||
continue
|
||||
}
|
||||
if _, ok := networkMap[network.NetID]; ok {
|
||||
continue
|
||||
}
|
||||
networkMap[network.NetID] = struct{}{}
|
||||
networks = append(networks, network)
|
||||
}
|
||||
|
||||
slog.Debug("returned user gws", "user", username, "gws", userGws)
|
||||
logic.ReturnSuccessResponseWithJson(w, r, networks, "fetched user accessible networks")
|
||||
}
|
||||
|
||||
// @Summary Get Users Remote Access Gw Networks.
|
||||
// @Router /api/users/{username}/remote_access_gw [get]
|
||||
// @Tags Users
|
||||
// @Param username path string true "Username to fetch all the gateways with access"
|
||||
// @Success 200 {object} map[string][]models.UserRemoteGws
|
||||
// @Failure 500 {object} models.ErrorResponse
|
||||
func getUserRemoteAccessNetworkGateways(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
username := r.Header.Get("user")
|
||||
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
|
||||
}
|
||||
network := params["network"]
|
||||
if network == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params network"), "badrequest"))
|
||||
return
|
||||
}
|
||||
userGws := []models.UserRAGs{}
|
||||
|
||||
userGwNodes := proLogic.GetUserRAGNodes(*user)
|
||||
for _, node := range userGwNodes {
|
||||
if node.Network != network {
|
||||
continue
|
||||
}
|
||||
|
||||
host, err := logic.GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
userGws = append(userGws, models.UserRAGs{
|
||||
GwID: node.ID.String(),
|
||||
GWName: host.Name,
|
||||
Network: node.Network,
|
||||
IsInternetGateway: node.IsInternetGateway,
|
||||
Metadata: node.Metadata,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
slog.Debug("returned user gws", "user", username, "gws", userGws)
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userGws, "fetched user accessible gateways in network "+network)
|
||||
}
|
||||
|
||||
// @Summary Get Users Remote Access Gw Networks.
|
||||
// @Router /api/users/{username}/remote_access_gw [get]
|
||||
// @Tags Users
|
||||
// @Param username path string true "Username to fetch all the gateways with access"
|
||||
// @Success 200 {object} map[string][]models.UserRemoteGws
|
||||
// @Failure 500 {object} models.ErrorResponse
|
||||
func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) {
|
||||
// set header.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
username := r.Header.Get("user")
|
||||
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
|
||||
}
|
||||
remoteGwID := params["access_point_id"]
|
||||
if remoteGwID == "" {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params access_point_id"), "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
|
||||
}
|
||||
|
||||
userGwNodes := proLogic.GetUserRAGNodes(*user)
|
||||
if _, ok := userGwNodes[remoteGwID]; !ok {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access denied"), "forbidden"))
|
||||
return
|
||||
}
|
||||
node, err := logic.GetNodeByID(remoteGwID)
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch gw node %s, error: %v", remoteGwID, err), "badrequest"))
|
||||
return
|
||||
}
|
||||
host, err := logic.GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch gw host %s, error: %v", remoteGwID, err), "badrequest"))
|
||||
return
|
||||
}
|
||||
network, err := logic.GetNetwork(node.Network)
|
||||
if err != nil {
|
||||
slog.Error("failed to get node network", "error", err)
|
||||
}
|
||||
var userConf models.ExtClient
|
||||
allextClients, err := logic.GetAllExtClients()
|
||||
if err != nil {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
for _, extClient := range allextClients {
|
||||
if extClient.Network != network.NetID || extClient.IngressGatewayID != node.ID.String() {
|
||||
continue
|
||||
}
|
||||
if extClient.RemoteAccessClientID == req.RemoteAccessClientID && extClient.OwnerID == username {
|
||||
userConf = extClient
|
||||
userConf.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
|
||||
}
|
||||
}
|
||||
if userConf.ClientID == "" {
|
||||
// create a new conf
|
||||
userConf.OwnerID = user.UserName
|
||||
userConf.RemoteAccessClientID = req.RemoteAccessClientID
|
||||
userConf.IngressGatewayID = node.ID.String()
|
||||
|
||||
// set extclient dns to ingressdns if extclient dns is not explicitly set
|
||||
if (userConf.DNS == "") && (node.IngressDNS != "") {
|
||||
userConf.DNS = node.IngressDNS
|
||||
}
|
||||
|
||||
userConf.Network = node.Network
|
||||
host, err := logic.GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
fmt.Sprintf("failed to get ingress gateway host for node [%s] info: %v", node.ID, err))
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
listenPort := logic.GetPeerListenPort(host)
|
||||
if host.EndpointIP.To4() == nil {
|
||||
userConf.IngressGatewayEndpoint = fmt.Sprintf("[%s]:%d", host.EndpointIPv6.String(), listenPort)
|
||||
} else {
|
||||
userConf.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
|
||||
}
|
||||
userConf.Enabled = true
|
||||
parentNetwork, err := logic.GetNetwork(node.Network)
|
||||
if err == nil { // check if parent network default ACL is enabled (yes) or not (no)
|
||||
userConf.Enabled = parentNetwork.DefaultACL == "yes"
|
||||
}
|
||||
if err = logic.CreateExtClient(&userConf); err != nil {
|
||||
slog.Error(
|
||||
"failed to create extclient",
|
||||
"user",
|
||||
r.Header.Get("user"),
|
||||
"network",
|
||||
node.Network,
|
||||
"error",
|
||||
err,
|
||||
)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
}
|
||||
userGw := models.UserRemoteGws{
|
||||
GwID: node.ID.String(),
|
||||
GWName: host.Name,
|
||||
Network: node.Network,
|
||||
GwClient: userConf,
|
||||
Connected: true,
|
||||
IsInternetGateway: node.IsInternetGateway,
|
||||
GwPeerPublicKey: host.PublicKey.String(),
|
||||
GwListenPort: logic.GetPeerListenPort(host),
|
||||
Metadata: node.Metadata,
|
||||
AllowedEndpoints: getAllowedRagEndpoints(&node, host),
|
||||
NetworkAddresses: []string{network.AddressRange, network.AddressRange6},
|
||||
}
|
||||
|
||||
slog.Debug("returned user gw config", "user", user.UserName, "gws", userGw)
|
||||
logic.ReturnSuccessResponseWithJson(w, r, userGw, "fetched user config to gw "+remoteGwID)
|
||||
}
|
||||
|
||||
// @Summary Get Users Remote Access Gw.
|
||||
// @Router /api/users/{username}/remote_access_gw [get]
|
||||
// @Tags Users
|
||||
|
@ -876,6 +1087,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) {
|
|||
network, err := logic.GetNetwork(node.Network)
|
||||
if err != nil {
|
||||
slog.Error("failed to get node network", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
gws := userGws[node.Network]
|
||||
|
|
|
@ -33,6 +33,7 @@ func InitPro() {
|
|||
proControllers.UserHandlers,
|
||||
proControllers.FailOverHandlers,
|
||||
proControllers.InetHandlers,
|
||||
proControllers.RacHandlers,
|
||||
)
|
||||
controller.ListRoles = proControllers.ListRoles
|
||||
logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() {
|
||||
|
|
|
@ -50,6 +50,9 @@ func NetworkPermissionsCheck(username string, r *http.Request) error {
|
|||
if targetRsrc == "" {
|
||||
return errors.New("target rsrc is missing")
|
||||
}
|
||||
if r.Header.Get("RAC") == "true" && r.Method == http.MethodGet {
|
||||
return nil
|
||||
}
|
||||
if netID == "" {
|
||||
return errors.New("network id is missing")
|
||||
}
|
||||
|
|
|
@ -511,6 +511,31 @@ func HasNetworkRsrcScope(permissionTemplate models.UserRolePermissionTemplate, n
|
|||
_, ok = rsrcScope[rsrcID]
|
||||
return ok
|
||||
}
|
||||
|
||||
func DoesUserHaveAccessToRAGNode(user models.User, node models.Node) bool {
|
||||
userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user)
|
||||
logger.Log(3, fmt.Sprintf("User Gw Access Scope: %+v", userGwAccessScope))
|
||||
_, allNetAccess := userGwAccessScope["*"]
|
||||
if node.IsIngressGateway && !node.PendingDelete {
|
||||
if allNetAccess {
|
||||
return true
|
||||
} else {
|
||||
gwRsrcMap := userGwAccessScope[models.NetworkID(node.Network)]
|
||||
scope, ok := gwRsrcMap[models.AllRemoteAccessGwRsrcID]
|
||||
if !ok {
|
||||
if scope, ok = gwRsrcMap[models.RsrcID(node.ID.String())]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if scope.VPNaccess {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetUserRAGNodes(user models.User) (gws map[string]models.Node) {
|
||||
gws = make(map[string]models.Node)
|
||||
userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user)
|
||||
|
|
Loading…
Add table
Reference in a new issue